This guide is for developers who wish to continue developing GeeKeep.
GeeKeep is a simple Command-Line-Interface (CLI) based Task Manager app. It is a Task Manager for users who prefer typing over reliance on GUI. In this guide, you can find information which is helpful in getting started as a GeeKeep contributor with respect to the code, tests, and design of the architecture.
In order to better contribute, you should:
- Be proficient in object-oriented programming with Java.
- Be familiar with libraries, e.g. JavaFX, used by GeeKeep.
- Be familiar with testing frameworks, e.g. JUnit, used by GeeKeep.
- Follow the Java coding standard.
-
JDK
1.8.0_60
or laterHaving any Java 8 version is not enough.
This app will not work with earlier versions of Java 8. -
Eclipse IDE
-
e(fx)clipse plugin for Eclipse (Follow the instructions given in this page from Step 2 onwards.)
-
Buildship Gradle Integration plugin from the Eclipse Marketplace
-
Checkstyle Plug-in plugin from the Eclipse Marketplace or its official website
- 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 auto-changed any settings files during the import process, you can discard those changes.
- Click
Project
->Properties
->Checkstyle
->Local Check Configurations
->New...
. - Choose
External Configuration File
underType
. - Enter an arbitrary configuration name e.g. GeeKeep.
- Import checkstyle configuration file found at
config/checkstyle/checkstyle.xml
. - Click OK once, go to the
Main
tab, use the newly imported check configuration. - Tick and select
files from packages
, clickChange...
, and select theresources
package. - Click OK twice. Rebuild project if prompted.
Note to click on the
files from packages
text after ticking in order to enable theChange...
button.
Problem: Eclipse reports compile errors after new commits are pulled from Git
- Reason: Eclipse fails to recognize new files that appeared due to the Git pull.
- Solution: Refresh the project in Eclipse:
Right click on the project (in Eclipse package explorer), chooseGradle
->Refresh Gradle Project
.
Problem: Eclipse reports some required libraries missing
- Reason: Required libraries may not have been downloaded during the project import.
- Solution: Run tests using Gradle once (to refresh the libraries).
Figure 2.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.
Main
has only one class called MainApp
. It is responsible for:
- App Launching: initialize the components in the correct sequence, and connect them up with each other.
- Shutting Down: shut down the components and invoke cleanup method where necessary.
Commons
represents a collection of classes used by multiple other components.
Two of those classes play important roles at the architecture level.
EventsCentre
: This class (written using Google's Event Bus library) is used by components to communicate with other components using events (i.e. a form of Event Driven design).LogsCenter
: Used by many classes to write log messages to the App's log file.
The rest of the app consists four components:
UI
: Renders the UI.Logic
: Parses and executes commands.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 its API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class.
Events-Driven nature of the design
The Sequence Diagram below shows how the components interact for the scenario where the user issues the
command delete 1
.
Figure 2.3a : Component interactions for delete 1
command (part 1)
Note how the
Model
simply raises aGeeKeepChangedEvent
when the Task Manager data are changed, instead of asking theStorage
to save the updates to the hard disk.
The diagram below shows how the EventsCenter
reacts to that event, which eventually results in the updates
being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
Figure 2.3b : Component interactions for delete 1
command (part 2)
Note how the event is propagated through the
EventsCenter
to theStorage
andUI
withoutModel
having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct coupling between components.
The sections below give more details of each component.
Author: Liu Ziyang
Figure 2.4 : Class Diagram of the UI Component
API : Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, EventListPanel
, FloatingTaskListPanel
, DeadlineListPanel
,
StatusBarFooter
etc. All these, including the MainWindow
, directly or indirectly inherit from the abstract UiPart
class
and they can be loaded using the UiPartLoader
.
The UI
component uses 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
. Some UI parts, for example, EventListPanel
are using JFoenix Library to realize material design.
The UI
component:
- Executes user commands using the
Logic
component. - Binds itself to some data in the
Model
so that the UI can auto-update when data in theModel
change. - Responds to events raised from various parts of the app and updates the UI accordingly.
_Figure 2.5 : Class Diagram of the Logic Component_
API : Logic.java
The Logic
component:
- Parses the user command using each command's respective
Parser
. - Executes a
Command
object based on the command and user input. - Encapsulates the result, a feedback
string
in aCommandResult
object.
For example, the following is what happens when the API execute("delete 1")
is called:
LogicManager
parses the user command using theParser
class.Parser
subsequently usesDeleteCommandParser
to parse the argument1
.- This results in a
DeleteCommand
object which is returned toLogicManager
. LogicManager
executes theDeleteCommand
object.- The command execution can affect the
Model
(e.g. adding a task) and/or raise events. - The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete 1")
API call.
Figure 2.6 : Interactions Inside the Logic Component for the delete 1
Command
_Figure 2.7 : Class Diagram of the Model Component_
API : Model.java
The Model
component:
- Stores a
UserPref
object that represents the user's preferences. - Stores the Task Manager data.
- Exposes a
UnmodifiableObservableList<ReadOnlyTask>
that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - Does not depend on any of the other three components.
_Figure 2.8 : Class Diagram of the Storage Component_
API : Storage.java
The Storage
component:
- Can save
UserPref
objects in JSON format and read it back. - Can save the Task Manager data in XML format and read it back.
You can find classes used by multiple components in the seedu.geekeep.commons
package. Here are some examples of common classes:
IllegalValueException
class used by bothLogic
andModel
components is responsible for throwing an exception when the value is considered invalid.UnmodifiableObservableList
class used byLogic
,Model
andStorage
components is responsible for providing an unmodifiable view of an observable list.LogsCenter
class used by all components is responsible for creating named loggers which you can further use to log messages and debug your code.
You can find implementation of logging in java.util.logging
package. The LogsCenter
class is used to manage the logging levels
and logging destinations.
- You can control the logging level using the
logLevel
setting in the configuration file (See Configuration). - To create a
Logger
for a class and log messages according to the specified logging level, you can useLogsCenter.getLogger(Class)
. - 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 are not noteworthy but may be useful in debugging e.g. print the actual list instead of just its size.
You can control certain properties of the application (e.g app name, logging level) through the configuration file. By default, config.json
will be created, when the configuration file is missing. To modify the configuration, you can either directly change the default config.json
file or create another json file and pass it to the app as an application parameter before running.
A typical configuration file should have the following format:
{
"appTitle" : "GeeKeep - Command Line Featured Task Manager",
"logLevel" : "INFO",
"userPrefsFilePath" : "preferences.json",
"geeKeepFilePath" : "data/geekeep.xml",
"geeKeepName" : "MyGeeKeep"
}
Note: If you are going to create your own configuration file, remember to stick to the format given above.
GeeKeep uses JUnit as the main testing framework and you can find all the tests in the ./src/test/java
folder.
In Eclipse:
- To run all tests, right-click on the
src/test/java
folder and chooseRun as
>JUnit Test
. - To run a subset of tests, you can right-click on a test package, test class, or a test and choose to run as a JUnit test.
Using Gradle:
- See UsingGradle.md for how to run tests using Gradle.
There are two types of tests in this project:
-
GUI Tests - These are System Tests that test the entire app by simulating user actions on the GUI. These are in the
guitests
package. -
Non-GUI Tests - These are tests not involving the GUI. They include,
- Unit tests targeting the lowest level methods/classes.
e.g.seedu.geekeep.commons.UrlUtilTest
- Integration tests that are checking the integration of multiple code units
(those code units are assumed to be working).
e.g.seedu.geekeep.storage.StorageManagerTest
- Hybrids of unit and integration tests. These test are checking multiple code units as well as
how the are connected together.
e.g.seedu.geekeep.logic.LogicManagerTest
- Unit tests targeting the lowest level methods/classes.
Headless GUI Testing
Fortunately, because this project uses the TestFX library, you can
run GUI tests in headless mode where the GUI tests do not show up on the screen.
This means you can do other things on the computer while the tests are running.
See UsingGradle.md to learn how to run tests in headless mode.
Problem: Tests fail because NullPointException when AssertionError is expected
- Reason: Assertions are not enabled for JUnit tests. This can happen if you are not using a recent Eclipse version (i.e. Neon or later)
- Solution: Enable assertions in JUnit tests as described
here.
Delete run configurations created when you ran tests earlier.
In this project, Coveralls is used to track how many statements are executed by test cases over time. You can check the current coverage report here.
A sample coverage report looks like Figure 4.1 given below:
Figure 4.1 Sample Coverage Report
If you click any of the source files in the report, for example, InvalidDataTimeException
in Figure 4.2, you can find uncovered lines colored with red:
Figure 4.2 Coverage Report for InvalidDataTimeException
Referring to the coverage report, you are welcome to pick source files with low coverage and write more test cases to improve the percentage of code coverage.
See UsingGradle.md to learn how to use Gradle for build automation.
This project uses Travis CI and AppVeyor to perform Continuous Integration. See UsingTravis.md and UsingAppVeyor.md for more details.
Here are the steps to create a new 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 your created.
You are recommended to use Google Chrome for converting documentation to PDF format, as Chrome's PDF engine preserves hyperlinks used in webpages.
Here are the steps to convert the project documentation files to PDF format:
- Make sure you have set up GitHub Pages as described in UsingGithubPages.md.
- Using Chrome, go to the GitHub Pages version of the
documentation file.
e.g. For UserGuide.md, the URL will behttps://<your-username-or-organization-name>.github.io/geekeep/docs/UserGuide.html
. - Click on the
Print
option in Chrome's menu. - Set the destination to
Save as PDF
, then clickSave
to save a copy of the file in PDF format.
For best results, use the settings indicated in the screenshot below.
Figure 5.1 : Saving documentation as PDF files in Chrome
A project often depends on third-party libraries or testing frameworks. For example, GeeKeep depends on the Jackson library for JSON parsing. A full list of GeeKeep's dependencies can be found in README.md.
Managing these dependencies
can be automated using Gradle. For example, Gradle can download the dependencies automatically, which
is better than these alternatives:
- Include those libraries in the project's repo (this bloats the repo size)
- Require you to download those libraries manually (this creates extra work for you)
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 the app |
* * * |
user | add a new task with title | add a floating task |
* * * |
user | add a new task with title and ending time | add a deadline |
* * * |
user | add a new task with title, starting time and ending time | add an event |
* * * |
user | list tasks | have a look at all my tasks |
* * * |
user | list unfinished tasks | see all the tasks I have yet to complete |
* * * |
user | update title, starting time or ending time of a task | change the task title, starting and ending time in case of a mistake or change of plans |
* * * |
user | mark a task as done or undone | keep track of completeness of the task |
* * * |
user | delete a task | forget about it |
* * * |
user | undo previous command | revert the most recent command |
* * * |
user | search the tasks by title | find a specific task without listing all of them |
* * * |
user | change file location for the data storage | |
* * * |
user | type command parameters in arbitrary order | have flexibility in typing commands |
* * * |
advanced user | use short versions of commands | type a command faster |
* * |
user | redo last undo command | revert the most recent undo command |
* * |
user | redo last command | repeat the most recent command |
* * |
user | add a recurring task | have the same task repeat itself over a specified duration without manually adding all of them |
* * |
user | add a task with description | have miscellaneous details not clutter the task title |
* * |
user | add a task with a description | see description that task takes place |
* * |
user | add a task with a tag | categorize the task |
* * |
user | list upcoming tasks for the week | see all the upcoming tasks from now till the end of the week |
* * |
user | list all tasks for the day | see an summary of tasks for the day |
* * |
user | list all tasks having the same tags | see an summary of tasks for the category |
* * |
user | search the tasks by description | find a specific task without listing all of them |
* * |
user | search the tasks by venue | find a specific task without listing all of them |
* * |
user | search tasks within a time period | find tasks within a time period without listing all of them |
* * |
user | filter the listed or search results by title, description, time or tag | find a specific task without looking through all of them |
* * |
user | set more than one filter for searching tasks | find desired tasks more easily |
* |
user | add a task with multiple time periods | confirm the exact start and end time for the task later |
* |
user | delete or update one of the multiple time periods of a task | update the exact start and end time for the task |
* |
user | create an alias for a long command | save time typing |
* |
user who also uses Google Calendar | sync tasks to Google Calendar | see existing tasks and add local tasks to Google Calendar |
(For all use cases below, the System is the GeeKeep and the Actor is the user, unless specified otherwise)
Use case: UC01 - Reschedule a task
MSS:
-
User requests to list tasks or search tasks.
-
GeeKeep shows an indexed list of tasks.
-
User requests to update the starting time or ending time of a specific task.
-
GeeKeep updates that task with new value.
-
GeeKeep shows the updated task
Use case ends.
Extensions:
2a. The task does not exist.
Use case ends.
3a. The given index is invalid.
3a1. GeeKeep shows an error message.
Use case resumes at step 2.
3b. The format of new starting time or ending time is invalid.
3b1. GeeKeep shows an error message.
Use case resumes at step 3.
3c. The given ending time is smaller than the starting time format.
3c1. GeeKeep shows an error message.
Use case resumes at step 3.
Use case: UC02 - Add a deadline
MSS:
-
User add a task without starting date but with an ending date.
-
Geekeep adds the deadline to the respective panel. Use case ends.
Extensions:
2a. There is a duplicate task.
2a1. Geekeep shows an error message.
Use case ends.
Use case: UC03 - Add an event
MSS:
-
User add a task with starting date and ending date.
-
Geekeep adds the event to the respective panel. Use case ends.
Extensions:
2a. There is a duplicate task.
2a1. Geekeep shows an error message.
Use case ends.
2b. The starting date of the event is after the ending date.
2b1. Geekeep shows an error message.
Use case ends.
Use case: UC04 - Mark a task as done
MSS:
-
User mark a task as done with its index.
-
Geekeep marks the task as done. Use case ends.
Extensions:
2a. The task associated with the index is not found.
2a1. Geekeep shows an error message.
Use case ends.
Use case: UC05 - Mark a task as undone
MSS:
-
User mark a task as undone with its index.
-
Geekeep marks the task as undone. Use case ends.
Extensions:
2a. The task associated with the index is not found.
2a1. Geekeep shows an error message.
Use case ends.
Use case: UC06 - Display completed tasks
MSS:
-
User requests all the tasks that are already done.
-
Geekeep refreshes the panels with completed tasks. Use case ends.
Extensions:
2a. There are no completed tasks.
2a1. Geekeep displays nothing in the panels.
Use case ends.
Use case: UC07 - Display uncompleted tasks
MSS:
-
User requests all the tasks that are not already done.
-
Geekeep refreshes the panels with completed tasks. Use case ends.
Extensions:
2a. There are no uncompleted tasks.
2a1. Geekeep displays nothing in the panels.
Use case ends.
Use case UC08 - Display tasks by tags
MSS:
-
User requests all the tasks associated with the given tags.
-
Geekeep refreshes the panels with tasks associated with the given tags. Use case ends.
Extensions:
2a. There are no tasks associated with the given tags.
2a1. The panels display nothing.
Use case ends.
Use case UC09 - Find a task with name
MSS:
-
User request tasks with given name.
-
Geekeep returns all the tasks with names that contains the given word. Use case ends.
Extensions:
2a. There are no matching tasks.
2a1. The panals display nothing
Use case ends.
Use case UC10 - Undo the preview command
MSS:
-
User requests to undo the previous command.
-
Geekeep retrieve the previous state of the task manager.
-
Geekeep replaces the current state with the previous state and refresh task cards. Use case ends.
Extensions:
2a. There is no command to undo.
2a1. Geekeep ignores the undo command.
Use case ends.
Use case UC11 - Redo the previous command
MSS:
-
User requests to redo the previous undo command.
-
Geekeep retrieves the saved state before the undo command.
-
Geekeep replaces the current state with the retreived state and refresh task cards. Use case ends.
2a. There is no command to redo.
2a1. Geekeep ignores the redo command.
Use case ends.
-
Should work on Windows 7 or later as long as it has Java 1.8.0_60 or higher installed.
-
Should not require any installation apart from Java.
-
Core features should be available and work even when offline.
-
Data storage should be in plain text and be easily readable and editable.
-
A user 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.
-
Should be free and come with open sourced code.
-
Users should be able to execute all commands by using the CLI alone
Mainstream OS
Windows, Linux, Unix, OS-X
Task
A task may or may not have a specific starting or ending time
Floating Task
A task without starting or ending time is a floating task (e.g., wash clothes).
Deadline
A task only with a specified ending time is a deadline (e.g., submit report).
Event
A task with both starting and ending time is an event (e.g., do an internship).
Author: Goh Yi Rui
Pros:
-
Support for lists, plain text, and pictures
-
Support for typing and voice recording
-
Color coding tasks
-
Easily searching through all tasks by name, label, color or category
-
Personalised labels or tags
-
Automatically identifying tasks that lie within a same category
-
Autocompletion and suggestion for tasks
-
Synchronization to Google Account
Cons:
-
Reliance on GUI for all operations
-
No support for events, only tasks and notes
-
Only online access
-
No project management features
Author: Zhang Hanming
Pros:
-
Automatically parsing emails and adding events to calendar
-
Reminders
-
Intuitive UI
-
Categorization of events
-
Allowing importing and exporting calendars
Cons:
-
Requiring a Google account
-
Not allowing checking off completed tasks
-
A calendar more than a task manager
Author: Liu Ziyang
Pros:
-
Allowing marking a task as done
-
Allowing postponing a task
-
Shortcuts for editing tasks
-
Personalised categorization
-
Integration with Google Calendar
Cons:
-
Only online access
-
No support for command line inputs
-
No support for events
-
No support for undoing an action
-
Poor UI with no displaying difference between urgent and non-urgent tasks
Author: How Si Wei
Pros:
-
Gamification and thus more motivation
-
Intuitive UI
-
Categorization of events through tags
-
Support for exporting data
-
A large number of official and user-created apps and extensions
Cons:
-
Requiring a Habitica account
-
A possible distraction due to gamification
-
Advanced features like group plans restricted to paid users