Project: iContacts
iContacts is an address book application targeted to university students for managing contacts. iContacts is a Command Line Interface (CLI) application where most of the interactions are through typing commands on a keyboard. It has a Graphical User Interface (GUI) created with JavaFX, and is written in Java with about 12 kLoC. iContacts allow users to manage reminders, keep track of upcoming contacts' birthday, as well as share the contact list using the application’s import and export mechanism.
This portfolio highlights the features and enhancements I have contributed to the development of iContacts, lists my enhancement proposal for the upcoming features, and also includes other contributions I have made. It also showcases the application of software engineering skills I have learned during the development.
Code contributed: [Functional code] [Test code]
Adding a nickname to a person : nickname
Adds a nickname to an existing person in the address book.
Format: nickname INDEX [NICKNAME]
Examples:
-
nickname 1 Eddie
Adds a nicknameEddie
to the 1st person. -
nickname 1
Removes the nickname from the the 1st person.
End of Extract
Justification
-
Users may want to add nickname to contacts in order to identify them easily, especially if the users have many contacts.
-
The nickname serves as an additional field that can be searched using the
find
command.
Finding all people by name and associated with one or more tags: filter
Finds persons whose names and/or tag(s) contain any of the given keywords.
Format: filter [n/NAME] [t/TAG]
Examples:
-
filter n/John
Returnsjohn
andJohn Doe
-
filter n/John n/Doe
or
filter n/John Doe
Returns any person with bothJohn
andDoe
in his name. -
filter t/friends
Returns any persons with the tagfriends
. -
filter t/friends t/colleagues
or
filter t/friends colleagues
Returns any person with the tagfriends
andcolleagues
. -
filter n/John t/friends
Returns any person having the nameJohn
and with the tagfriends
.
End of Extract
Justification
-
Users may need a more precise search.
-
The current
find
command lists the contacts that match any of the keywords (i.e. anOR
search). -
The
filter
command is much more restrictive as it lists the contacts that match all the keywords (i.e. anAND
search). -
The name and tags are used as the field for the filter command as they are most likely to be used as constraints in the search.
Filter mechanism
The FilterCommand
uses the NameAndTagsContainsKeywordsPredicate
to filter the persons with matching name and/or tags. It accepts the List<String> nameKeywords
and List<String> tagKeywords
as parameters that are parsed by the FilterCommandParser
. The code snippet below is the constructor for the class:
public class NameAndTagsContainsKeywordsPredicate {
public NameAndTagsContainsKeywordsPredicate(List<String> nameKeywords, List<String> tagKeywords) {
this.nameKeywords = nameKeywords;
this.tagKeywords = tagKeywords;
}
}
The method test(ReadOnlyPerson person)
iterates through the nameKeywords
and the tagKeywords
to find a match of every person
from the address book.
Below is an extract of the method test(ReadOnlyPerson person)
. The method countTagMatches(person)
counts and returns the number of matches between the tags of the person
and the tags in the tagKeywords
. If the tagsMatchedCount
is equal to the size of the tagKeywords
, this means all the keywords in the tagKeywords
match. The hasTag
will then be set to true
.
public class NameAndTagsContainsKeywordsPredicate {
@Override
public boolean test(ReadOnlyPerson person) {
boolean hasTag = false;
int numTagKeywords = tagKeywords.size();
int tagsMatchedCount = 0;
if (!tagKeywords.isEmpty()) {
tagsMatchedCount = countTagMatches(person);
}
if (tagsMatchedCount == numTagKeywords) {
hasTag = true;
}
}
Below is an extract of the same method for name. Each keywords in the nameKeywords
will be compared against the name list retrieved from the getName()
method of the Person
class. If all the keywords match, the hasName
will be set to true
.
public class NameAndTagsContainsKeywordsPredicate {
@Override
public boolean test(ReadOnlyPerson person) {
boolean hasName = false;
if (!nameKeywords.isEmpty()) {
hasName = nameKeywords.stream().allMatch(nameKeywords -> StringUtil
.containsWordIgnoreCase(person.getName().fullName, nameKeywords));
}
}
}
For the FilterCommand
to work properly, either the nameKeywords
or the tagKeywords
must be non-empty.
Design Considerations
Aspect: Should similar search commands be separated
Alternative 1 (current choice): Create a separate command to search for contacts that match all keywords.
Pros: Users will not be confused between the functionality of the find
and filter
commands.
Cons: Users have to remember an additional command.
Alternative 2: Modify the FindCommand
to allow users the option to search contacts that either match any keywords or match all keywords.
Pros: Lesser command for the users to remember when searching for contacts.
Cons: Implementation can be more complicated as there is a need to address both OR
search and AND
search on the same command.
End of Extract
Changing the theme : theme
Changes the theme of the address book to a specific theme.
Format: theme THEME
Examples:
-
theme day
Changes the theme today
(Refer to Figure 11).
Figure 11: Theme changed to day
.
End of Extract
Justification
-
Users can have more choices of theme to set for iContacts.
-
Users may find it easier to use iContacts if they are working on their preferred theme.
Theme-changing mechanism
Figure 39 : Component interactions for the theme-changing mechanism
The theme-changing mechanism is an event-driven mechanism. The above diagram (Refer to Figure 39) shows the high-level overview of the component interactions for the theme-changing mechanism.
Figure 40 : Sequence diagram for the first part of the theme-changing mechanism
As shown from the sequence diagram above (Refer to Figure 40), after the user entered the command theme day
, a new object ThemeCommand
will be created. The LogicManager
will then execute ThemeCommand
, and the event ChangeThemeRequestEvent
will be posted by EventsCenter
. The code snippet below shows the execute()
method of ThemeCommand
:
public class ThemeCommand extends Command { @Override public CommandResult execute() { EventsCenter.getInstance().post(new ChangeThemeRequestEvent(theme)); return new CommandResult(String.format(MESSAGE_SET_THEME_SUCCESS, theme.getTheme())); } }
Figure 41 : Sequence diagram for the second part of the theme-changing mechanism
As shown from the sequence diagram above (Refer to Figure 41), the method handleChangeThemeEvent()
in MainWindow
will handle the event and change the theme of the address book through the method changeTheme()
accordingly.
Design Considerations
Aspect: Implementation of ThemeCommand
Alternative 1 (current choice): Utilize ChangeEventRequestEvent
that allow MainWindow
to handle the event to change the theme.
Pros: ThemeCommand
can be more efficient since it does not directly change the theme.
Cons: New developers may find it difficult to understand the event-driven nature of the application.
Alternative 2: Allow ThemeCommand
to set the theme directly by allowing it access to MainWindow
.
Pros: Easier for new developers to understand.
Cons: Violates the architectural style as ThemeCommand
belongs to the Logic
component that should not be able to access the UI
component where MainWindow
belongs to.
End of Extract
Enhancement Proposed: Enhance the command filter
-
Users will be able to perform an even more precise search using more fields as constraints (e.g. nickname, birthday).
-
Users will also able to perform search for keywords that are incomplete (e.g. filtering
Ben
will also matchBenson
).
Enhancement Proposed: Enhance the command theme
to allow customised theme
-
Users will be able to customise the theme of their choice.
-
Users will be able to import their own CSS file to update the theme.
Enhancement Proposed: Add a new command listtag
-
Users will be able to list all tags they have used when adding or editing the contacts.
-
This allow the users to keep track of all the tags used.
Enhancement Proposed: Merge the command nickname
to the command add
and edit
-
Users will be able to add, edit or remove the nickname of contact through the
add
andedit
command. -
Since the nickname is just another field for the contact, it would be better to add and edit the nickname using the
add
andedit
command respectively without thenickname
command.
Other contributions
-
Conducted acceptance testing on another team project and uncovered bugs (see issue #48, #49, #51, #52).
-
Wrote additional tests to increase coverage slightly (see pull requests #93, #180).
-
Wrote descriptions of iContacts and target audience in the README.adoc (see pull request #250).
-
Wrote part of the TestScript.adoc (see pull requests #232, #233).
-
Corrected the grammatical errors in the User Guide and Developer Guide (see pull requests #202, #214).
-
Corrected my teammates' grammatical errors in the Developer Guide (see pull requests #263, #265).
-
Highlighted actions to be made to improve the quality of the User Guide and Developer Guide (see issue #169).