Overview
NUS Hangs is a desktop Schedule Manager application. It has a GUI but most user interactions occur on CLI (Command Line Interface). It is written in Java by developers of F11-4, to target small/mid-size interest/study groups in NUS.
Summary of contributions
-
Major enhancement: Created a group class and added corresponding group functions:
-
add_group: Add a new group which will appear in the right group panel of UI.
-
delete_group: Delete an existing group and remove all current members from that group.
-
edit_group: Edit an existing group’s name/description.
-
register: Register an existing person as a member of the group.
-
delete_member: Delete an existing member of the group.
-
find_group: Find a group based on its name.
-
view_group: View all members of the group in UI.
-
Justification: This feature improves the product’s functionality significantly because a user can now better organise his contacts into groups and easily coordinate common time slots to meet.
-
Highlights: This enhancement affects existing and future commands. The implementation was challenging due to:
-
Integration of Group and Person Class. For instance, delete_group requires the group to be deleted and all reference to the group in all Persons registered to be deleted.
-
Changes in the UI and Storage. For instance, GroupPanel has to be created to display groups. Group data have to stored after the app closes and reloaded into the app as Group objects when app is launched.
-
-
-
Minor enhancement: Enhance
list
command to list both groups and persons. Added alist INDEX
command to show all the groups that the person at INDEX is currently in. (#123) -
Minor enhancement: Created short forms for commands. (#208)
-
Minor enhancement: Created Abstract class Entity which Group and Person extends from to allow for polymorphism: Refactored the ModelManager and AddressBook function: E.g. addPerson() -→ add() which performs add on Group or Person class based on polymorphism. Also, refactored UniquePersonList into generic UniqueList<T>. (#80)
-
Minor enhancement: Created a defensiveSetGroups method in Person class enforcing compulsory association of Person and groupList- instead of setGroup() which can alter a private groupList field in Person and also checks for null entries of groupList (#222).
-
Code contributed: [Functional and Test code]
-
Other contributions:
-
Project management:
-
Managed releases
v1.1
-v1.3
(3 releases) on GitHub -
Edited the badges: Codacy badge, Coverage and Build status on README.adoc.
-
-
Enhancements to existing features:
-
Documentation:
-
Community:
-
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. |
Listing all groups a person is in : list
(Melodies)
Short form/Alias: l
Shows a list of all groups the person specified by his PERSON_INDEX is in.
Format: list PERSON_INDEX
(Remember to list
first)
Example:
-
list 1
(lists all the groups that the person at index 1 is added to previously)
Groups (Melodies)
Adding a group: add_group
(Short form/Alias: ag
)
Add a group to the System
Format: add_group n/GROUPNAME [d/GROUPDESCRIPTION]
Examples:
-
add_group n/happyfriends d/a group of happy friends
-
`add_group n/Bestfriends
Editing a group : edit_group
(Short form/Alias: eg
)
Edit a group’s details. OLDGROUPNAME must be entered. There must be at least 1 field non-empty. If field is empty, system assumes that the field remains unedited.
Format: edit_group OLDGROUPNAME [n/NEWGROUPNAME] [d/NEWGROUPDESCRIPTION]
Examples:
-
add_group n/happyfriends d/a group of happy friends
-
edit_group happyfriends n/sadfriends d/sad because of cs2103
(Changes the name of group from "happyfriends" to "sadfriends" and description) -
edit_group sadfriends d/very very miserable
(Changes only description.)
Locating group by name: find_group
(Short form/Alias: fg
)
Find groups whose names contain any of the given keywords
Format: find_group KEYWORD [MORE_KEYWORDS]
-
Only the group name is searched.
-
Only full words will be matched e.g.
Family
will not matchFamilies
Examples:
-
find_group John
Returnsjohn family
andJohn House
-
find_group Betsy Tim John
Returns any group having namesBetsy
,Tim
, orJohn
Deleting a group : delete_group
(Short form/Alias: dg
)
Delete a group in the system by name
Format: delete_group n/GROUPNAME
Examples:
-
delete_group n/happyfriends
Add a person to group : register
(Short form/Alias: r
)
Adds a person using the person index to a group if group exists
Format: register PERSON_INDEX n/GROUP_NAME
-
Remember to
list
before using register command.
Examples: (Adds the first person in the displayed person panel to the group happyfriends)
list
register 1 n/happyfriends
List all persons of a group : view_group
(Short form/Alias: vg
)
Displays a list of all persons in a group
Format: view_group n/GROUP_NAME
Examples: (lists the persons added to group happyfriends in the displayed person list)
-
` view_group n/happyfriends`
Delete a person from group : delete_member
(Short form/Alias: dm
)
Delete a person from a group using person index displayed with view_group
.
Format: delete_member PERSON_INDEX n/GROUP_NAME
-
Remember to
view_group
before using register command. -
The PERSON_INDEX is the index of the displayed person list AFTER
view_group
command is performed.
Examples: (deletes the 1st person displayed in view_group
command.)
-
view_group n/happyfriends
-
delete_member 1 n/happyfriends
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. |
Group Feature
The Group
class extends the Entity
abstract class just like a Person
class does. An Entity
contains an abstract method isSame
that is necessary for the class to be used in UniqueList<T extends Entity>
. Group
class is an immutable class that is contained inside Model
.
As shown in the diagram below, group and person classes are associated. Each group contains a UniqueList<Person>, a list of its members. Likewise, each person contains a UniqueList<Group>, a list of all groups he is in. Due to these mutual association, commands editing/deleting instances of group or person may have to edit the corresponding member/group lists respectively. (Refer to DeleteGroupCommand example below.)
Group
features make use of Storage
to load information on groups added by the user before the UI is closed. XmlAdaptedGroup
class helps the convert groups detail from xml files to the AddressBook
when MainApp
starts and similarly convert Group
objects into xml files.
Group
features also updates the Group Panel inside the UI
using a predicate.
Current Implementation
The current group commands added are:
-
add_group
/ag
— adds a group with an optional description -
delete_group
/dg
— deletes a group and all references from its members to it -
edit_group
/eg
— edit name/description of a group while maintaining uniqueness of all group names -
find_group
/fg
— search for groups using keywords that must match exactly a word in Group name -
register
/r
— register a member into an existing group and include a reference to the group in the member (Person class) -
delete_member
/dm
— delete an existing member from an existing group and remove reference to that group in the member -
view_group
/vg
— view the existing members in the group and is updated whenever any member is added or deleted. -
list [person_index]
/l [person_index]
— lists all the groups the person at[person_index]
is currently in.
These functions and their parsers are handled in Logic
, before updating Model
and Storage
and displaying the updated result on the UI
.
An Example: DeleteGroupCommand
The DeleteGroupCommand is a good example of how Group and Person classes are interacting (dependent and associated with each other). An example usage scenario of how delete_group
behaves at each stop is explained below.
Step 1: The user launches the application. (We assume that the user has already added a group and person.) VersionedAddressBook
will be loaded with the final addressbook state before the application was closed. Lists of groups and persons added previously will be loaded from addressbook.xml
file into Model
using XmlAdaptedPerson
and XmlAdaptedGroup
classes. Updated lists will be displayed in the UI
.
Step 2: The user enters the command dg n/Family
to delete the existing group with group name Family.
-
The
LogicManager
class parses the command toAddressBookParser
.AddressBookParser
creates aDeleteGroupCommandParser
instance which parses the String "Family" into aName
name. The parser creates aGroup
gr with the name (Family). This group is needed for the function below. -
The parser creates a
DeleteGroupCommand
object with parameters gr. Subsequently,retrieveGroupFromName(m, gr.getName())
is called to the Model component in order to retrieve the actual group with the name "Family".
-
After retrieving the actual group
g
with name "Family" from Modelm
, the model performs deletion of the group using an internal functiondelete(g)
. -
However, the group still has to be deleted from the groupList from all of its members. (Refer to GroupPersonClassDiagram above.)
deleteGroupFromMembers(m, g)
is called from DeleteGroupCommand object to do so. This method calls theUnModifiableObservableList()
method in its UniqueList<Person> to return a list ofmembers
ing
. For everymember
in the list ofmembers
(for loop),updatePersonDeleteGroupFromGroupList(m, g, member)
deletes the reference tog
inmember
. -
Finally, the address book is committed with all the changes.
Step 4: FilteredPersonList
and FilteredGroupList
is also updated correspondingly to display the new groups and persons in the UI
. A successful message is also displayed to the user below the UI’s command box.
Step 5: Before the application is closed, all groups and persons are stored in addressbook.xml
using XmlAdaptedGroup
and XmlAdaptedPerson
classes. (Refer to High level sequence diagrams Figure 3 and 4 for a similar illustration of the concept.)
Design Considerations
Aspect: How to implement Group
class
Alternative 1 (current choice): Group
as an immutable class.
Pros: Immutable objects are good Map keys and Set elements, since these typically do not change once created. Immutability makes it easier to write, use and reason about the code.
Cons: Doing so might restrict the way one can call the class and its methods. It may be slower as you have to create new objects with every command.
Alternative 2: Setter methods for Groups
Pros: Easier and less code for methods involving groups. Faster as do not have to create new objects each time you change a Group (e.g. edit its description or group members).
Cons: Miss out on the advantages of immutable object (above). Good practice to use immutable objects.
Aspect: Interactions between person and groups
Deleting a person from a group will affect the person’s reference to that group and vice versa (similar for adding and editing).
Alternative 1 (current choice): Having a UniqueList<Groups>
in Person
and UniqueList<Person>
in Group
.
Pros: Easy to retrieve groups from Person and persons from Group. Existing UniqueList
class available (since already used in Model
).
Cons: Have to update both lists in most group commands (e.g. registering a new member in a group). Issue of enforcing referential integrity - defensive programming.
Alternative 2 Just update the list of groups in Model
and have person refer to that list of group as to whether it is a member of the group.
Pros: Less issues with enforcing referential integrity (see alternative 1).
Cons: Can be more expensive to look for groups for a particular person.