Project: Mobilize
Mobilize is a desktop application built to help people organize their contacts and tasks. It is primarily written in Java and uses the Object Oriented Paradigm. The user interacts with it using a CLI, and it has a GUI created with JavaFX.
Code contributed: [Functional code] [Test code]
Enhancement Added: Add Task
Adding tasks: add
Whether it is a host of pending submissions, a get-together or a multiday program, adding it to Mobilize can easily help you keep track of it all.
Use prefixes:
Format: add DESCRIPTION [by/on/from DEADLINE] [at START TIME to END TIME] [t/TAG]…
-
The task added is automatically sorted according to the deadline. With expired tasks coming first, follow by tasks with deadline that are coming up next and lastly tasks without deadline.
-
If you want to enter a date, it must follow the MONTH-DAY-YEAR format.
-
Words or phrases like 'tomorrow', 'yesterday', 'Tue', 'Tuesday', 'day after tomorrow', '5 Dec', '5/9/2017' and 'the 8th of Jan' are all valid dates.
-
2 pm
,2:00
,02:00
,1400
are all valid times. -
Deadlines and times are optional items.
Examples:
-
add important meeting on 17 Nov at 9 am to 11 am
Sets the description toimportant meetin
, deadline to the15th of November
in the current or upcoming year and times to09:00
and11:00
respectively. -
add recess week from tomorrow by 15 Sep
Sets the description torecess week
start date to the next day and the deadline to the15th of September
in the current or upcoming year. -
add get groceries
Sets the description toget groceries
leaving the other parameters blank.
Constraints
Note the following constraints when adding tasks:
End of Extract
Justification
The Add Task command was the first step in expanding Mobilize’s capabilities. In allowing users to add pending tasks to their application, Mobilize has adopted the responsibility of organizing its user’s life.
The Add Task uses a Natural Language Parsing Library, PrettyTime, in order to make it more user-friendly, by allowing task dates to be set using natural language dates and times. This makes the command format of the application less rigid and increases its appeal to potential users.
AddTask mechanism
The Add Task mechanism is facilitated by the AddTaskCommand
class which inherits from the UndoableCommand
class. It allows for the addition of new tasks to the application with a starting date and a deadline. Both dates are optional and may be omitted.
Suppose the user has just executed the add
command using:
`add CS assignment by tomorrow at 23:59`.
At first, the command is called is called, which causes the LogicManager
to pass the command string into the parseCommand()
function of the AddressBookParser
class. This, in turn, determines that the AddTask
feature is being evoked and calls the AddTaskCommandParser
to parse the String and separate it into three components: Description
, StartDate
and Deadline
. These are validated and formatted by the Task
class and returned as a Task
object to be used to call the AddTaskCommand
class. The LogicManager
then calls the executeUndoableFunction()
in the AddTaskCommand
class which creates and returns a CommandResult
object.
The following sequence diagram summarizes how this operation works:

All parameters except the description are set to be optional wherein an empty string is added when no value is stated by a user.
Natural Language Input is processed by the PrettyTime NLP, in the ParserUtil
class in the following way:
public static Optional<EventTime[]> parseEventTimes(Optional<String> dateTime) throws IllegalValueException { requireNonNull(dateTime); if (dateTime.isPresent()) { List<DateGroup> dateGroup = new PrettyTimeParser().parseSyntax(dateTime.get().trim()); if (dateGroup.isEmpty()) { throw new IllegalValueException(DateTimeValidator.MESSAGE_TIME_CONSTRAINTS); } List<Date> dates = dateGroup.get(dateGroup.size() - 1).getDates();
String endTime = DateTimeFormatter.formatTime(dates.get(dates.size() - 1)); String startTime = dates.size() > 1 ? DateTimeFormatter.formatTime(dates.get(dates.size() - 2)) : "";
return Optional.of(new EventTime[]{new EventTime(startTime), new EventTime(endTime)}); } else { return Optional.empty(); } }
/** * Parses a {@code String naturalLanguageInput} using PrettyTime NLP, into a {@code Date}. * @throws IllegalValueException if the date cannot be parsed from the phrase or if the given date is invalid. */ public static Date parseDate(String naturalLanguageInput) throws IllegalValueException { List<DateGroup> dateGroup = new PrettyTimeParser().parseSyntax(naturalLanguageInput.trim()); if (dateGroup.isEmpty() | !DateTimeValidator.isDateValid(naturalLanguageInput)) { throw new IllegalValueException(DateTimeValidator.MESSAGE_DATE_CONSTRAINTS); } List<Date> dates = dateGroup.get(dateGroup.size() - 1).getDates(); return dates.get(dates.size() - 1); }
Design Considerations
Aspect: Creating classes for StartDate and Deadline
Alternative 1 (current choice): Use Strings to contains the StartDates and Deadlines.
Pros: * Easy to assign an empty string to the instance variable so that the dates are optional and do not show up in the UI.
In addition, dates can be stored after being formatted to a more user-friendly style (i.e. Tue, Oct 24, '17). This prevents dates from becoming confusing (i.e. distinguishing between dd-MM-yyyy and mm-DD-yyyy)
Cons: Dates are not stored the correct format. This makes it more difficult to compare and validate later on as they have to be reformatted into Date objects every time. For example,
in validating whether a start date is indeed before a deadline.
Alternative 2: Use java.time.LocalDate class.
Pros: Dates are in correct format. Validation becomes easier and reformatting is not necessary.
Cons: LocalDate cannot be initialized when no input is given. Using a phony value of 00:00 or the current date might cause errors in validation and sorting of dates.
Alternative 3: Use java.util.Optional class for instance variables along with the LocalDate class.
Pros: Easy to understand reasoning, for new developers looking to contribute. Easy to format specifically for display (once) and allows empty values when no dates are supplied.
Cons The general agreement in the software engineering community seems to be that it is better not to use extra wrapping for an instance variable, that might pose problems in unwrapping later on.
Aspect: Natural Language Processing
Alternative 1 (current choice): Use an external library (PrettyTime) to process dates in natural language after they have been tokenized by their respective prefixes
and categorized according to type.
Pros Dates are sure to be instantiated according to the correct class.
Cons Command format becomes less flexible.
Alternative 2: Parse all dates first then scan the argument string for keywords.
Pros More flexible command format and consequently, more user-friendly.
Cons Open to more mistakes in setting starting dates and deadlines.
Aspect: Setting prefixes for adding tasks
Alternative 1 (current choice): Use natural language prefixes i.e. from, to, by
Pros Easier to type and remember.
Cons Difficult to implement as descriptions containing these words must be separated from dates.
Alternative 2 Use slashes such as in task commands i.e. f/, o/, b/ etc.
Pros Faster to type.
Cons Description might contain slashes. t/ (to) would clash with t/ prefix for tags so to/ would have to be used.
Limits possibilities of adding new prefixes and making the format more flexible in the future.
End of Extract
Enhancement Added: Edit Task
Editing tasks: edit
Change of plans? The edit feature offers a hassle-free solution to change any parameter of an existing task.
Format: edit INDEX DESCRIPTION by/from/at DEADLINE at START TIME to END TIME
One or more parameters can be specified. |
The time parameter can only be edited using the prefix at .
|
For example:
-
edit 1 exam on 4th Dec at 8 pm to 9 pm
Changes all parameters of the task at INDEX 1 to set task description toexams
, deadline toMon, Dec 4, '17
and times to20:00
and21:00
respectively. -
edit 2 from tomorrow
Changes the deadline of the task at INDEX 2 to the date of the following day. -
edit 3 at 9 am
Changes the time of the task at INDEX 3 to09:00
.
Note the following constraints when editing tasks:
End of Extract
Justification
Editing tasks is a natural extension of the add task feature
EditTask Mechanism
The EditTask Mechanism is facilitated by the EditTaskCommand
class and allows th euser to edit any parameter of a given task.
Suppose the user has just executed the command:
edit 1 finish homework by sunday at 9 am to 12 pm
---
The command is passed by the LogicManager
class to the AddressBookParser
which goes on to pass it to the EditTaskCommandParser
class. Here a new EditTaskDescriptor
is created using the newly specified parameters while old parameters are copied. Finally,
a newly edited person is created and the Model is called to update the task using the UpdateTask()
method.
The following sequence diagram summarizes how this operation works:

The optional parameters are assigned in the following manner in the EditTaskCommandParser
:
parseDescriptionForEdit(argMultimap.getPreamble()).ifPresent(editTaskDescriptor::setDescription); parseDeadlineForEdit(argMultimap.getAllValues(PREFIX_DEADLINE_BY, PREFIX_DEADLINE_FROM, PREFIX_DEADLINE_ON)) .ifPresent(editTaskDescriptor::setDeadline); parseEventTimesForEdit(argMultimap.getAllValues(PREFIX_TIME_AT)) .ifPresent(editTaskDescriptor::setEventTimes); ParserUtil.parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editTaskDescriptor::setTags); ---
End of Extract
Enhancement Added: Tag Multiple Contacts and Tasks
Tagging multiple tasks : tag
Tags are a useful way of grouping and labeling tasks. But editing them manually, one by one, can be a tedious process. Instead, you can use the tag command to tag multiple tasks simultaneously.
Format: tag INDEX… t/[TAG]…
You can add multiple tags to multiple tasks by repeating the tag prefix. |
Example:
tag 1, 2, 3 t/urgent t/family
Results in all contacts in indices 1, 2 and 3 being tagged with both [urgent
] and [family
].
Constraints
Note the following constraints when trying to add tags:
End of Extract
Start of Extract [from: User Guide]
Tagging multiple contacts : tag
Tags are a useful way of grouping and labeling contacts. But editing them manually, one by one, can be a tedious process. Instead, you can use the tag command to tag multiple contacts simultaneously.
Format: tag INDEX… t/[TAG]…
You can add multiple tags to multiple contacts by repeating the tag prefix. |
Example:
tag 1, 2, 3 t/friend t/family
Results in all contacts in indices 1, 2 and 3 being tagged with both [friend
] and [family
].
Constraints
Note the following constraints when trying to add tags:
End of Extract
Justification
The rationale behind adding a special feature to add tags cumulatively, was primarily to open up a world of
possibilities of the tags themselves, to a user. Not only can they be used to effectively, yet easily organize contacts
and tasks - that too, by multiple parameters - but they can also be used to link the two with the same tag
to keep track of tasks with which people are associated and vice versa.
That being said, the caveat to consider was whether to create a new command or modify the edit command itself to allow for tagging cumulatively. In the end, it was decided that separating the two would help achieve the goal of helping users be better organized, as the edit function focuses solely on replacing existing tags or removing them altogether while the tag command serves to increment them. In addition, the flexible indexing for the tag command helps users tag their desired contact or task even if they make some mistakes in typing the index unlike the edit command.
Overall the tag command achieves the application’s purposes of organizing its user’s life much more efficiently.
Tag mechanism
The Tag mechanism is a specialised form of the edit feature that allows users to tag multiple contacts with multiple tags.
The mechanism is facilitated by the TagCommand
class which inherits from the UndoableCommand class, indicating that it can be undone.
Suppose the user has just executed the TagCommand
using:
`tag 1,2 t/friend t/classmate`.
At first the command is called, which causes LogicManager
to pass the command string to the parseCommand()
function of the AddressBookParser
class. This determines that the TagCommand
feature is being evoked
and calls the TagCommandParser
class.
Here, the arguments are validated and tokenized and new TagCommand
object is returned with parsed indices and tags.
The ModelManager
class in the Model
component is then called to update all the tags of the respective people using the updatePersonTags()
method.
The Storage and UI are subsequently updated with the new information.
The following sequence diagram summarizes how this operation works:

The TagCommand skips over the invalid indices and attempts to tag the contacts who are in the valid indices. If no valid indices are found, then an error is thrown. This is done by the following:
/** * Filters the valid indices in a given array of indices. */ public static Index[] filterValidIndices(int lastShownListSize, Index[] indices) { assert indices != null; assert lastShownListSize != 0; return Arrays.stream(indices) .filter(currentIndex -> currentIndex.getZeroBased() < lastShownListSize) .toArray(Index[]::new); }
Index[] validIndices = CommandUtil.filterValidIndices(lastShownList.size(), indices);
if (validIndices.length == 0) { throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); }
Other contributions
-
Added autocomplete feature using ControlsFX Library (Pull request #96).
-
Discovered bug during trial acceptance testing (Issue #103).
-
Rewrote large parts of the User Guide and Developer to enhance it (Pull Request #144) (Pull Request #112).
-
Reviewed and edited the language and structure of all documentation.
-
Generated SampleData.xml file (Pull Request #138).
-
Set up organization, Milestones and Issues.
-
Assisted other students in Slack.