Project: UniCity

UniCity is a desktop address book application used to help university students manage their ever-growing network. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 16 kLoC (16 000 Lines of Code).

Enhancement Added: sort command

External behavior


Start of Extract [from: User Guide]

Sorting a contact : sort

Sorts the list of contacts in UniCity by name.
Format:
sort
st

  • Sorts the list of contacts according to alphabetical order.

  • The names sorted are case-insensitive.

  • If there is no contact in the list, nothing will be sorted.

Example:

  • sort
    Sort the list of contacts in UniCity by ascending order.

End of Extract


Justification

The purpose of sorting the contacts is so that users could view their contacts in alphabetical order. This allows the user to find the necessary contact easier by simply glancing through UniCity in order.
Given a large number of contacts by university students, the user can always view their contacts in sorted order to scroll through their contacts list,

Implementation


Start of Extract [from: Developer Guide]

Sorting mechanism (Since v1.2)

The sorting mechanism is achieved by the SortCommand. In order to sort the list of contacts, the default constructor of SortCommand creates an empty editable array list of contacts as shown below:

private ArrayList<ReadOnlyPerson> contactList;
public SortCommand() {
    contactList = new ArrayList<>();
}

The new list will take in a list of contacts from address book, sort the contacts and overwrite the existing list of contacts in address book sorted by alphabetical order. The SortCommand inherits from Command instead of UndoableCommands so there is no mechanism for sorting to be undone.

The SortCommand is implemented in the following way:

public class SortCommand extends Command {
    @Override
    public CommandResult execute() {
        // ... sort logic ....
    }
}

When the command word sort or st is entered in UniCity, AddressBookParser will call SortCommandParser.

Upon calling the function, an editable contactList containing ReadOnlyPerson will be empty at the beginning.

When the user executes SortCommand, sort or st, to sort the list of contacts in address book. The current empty ArrayList of contactList will be sent to the model …​…​..

The following sequence diagram shows how the sort operation works:

SortCommandSequenceDiagram
public Boolean sortPersonByName(ArrayList<ReadOnlyPerson> contactList) {

    //check the condition of the list of contacts in addressbook currently
    //different Boolean value will be returned depending on the order of the contacts
    if (filteredPersons.size() == 0) {
        return null;
    }
    contactList.addAll(filteredPersons);
    Collections.sort(contactList, Comparator.comparing(p -> p.toString().toLowerCase()));

    if (contactList.equals(filteredPersons)) {
        return false;
    }
    try {
        addressBook.setPersons(contactList);
        indicateAddressBookChanged();
    }
    //...exceptions caught...
    return true;
}

Upon successful sorting, the SortCommand will correctly sort the contacts in alphabetical order and display the contacts under the PersonListPanel.

If there is an empty list, the address book will show a message saying No contact to be sorted.
If the list is in correct order, the address book will show a message saying Already sorted.

The sorting process is case insensitive.

Design considerations

Aspect: Implementation of SortCommand
Alternative 1 (current choice): The SortCommand will inherit directly from Command without the undo/redo mechanism.
Pros: After the user has finished sorting his list of contacts, it will remain sorted without reverting back to the original list.
Cons: The user can no longer obtain the list of contacts with the original order.
Alternative 2: The SortCommand will implement undo/redo mechanism.
Pros: All contacts will be able to return to the original order when undo is applied.
Cons: It may be troublesome for the user as he may want to undo a delete/add function but the list of contacts becomes unsorted and he must sort again.

Aspect: How sorting is executed
Alternative 1 (current choice): Sorting is accomplished using the in-built function in Collections to sort the arrays according to alphabetical order.
Pros: This method is straightforward and easy to implement.
Cons: The algorithm is in-built so it is harder to debug if something goes wrong.
Alternative 2: Writing my own sorting algorithm.
Pros: This method can cater to case sensitivity and other exceptions of the list when sorting is involved.
Cons: The algorithm may be more prone to error and may not be straightforward enough.

Aspect: Data structure to support the sort command
Alternative 1 (current choice): Create an empty array list to obtain the data from the contact list and sort the contacts. It will overwrite the existing array list of unsorted contacts when sorted.
Pros: This method is easier to understand and the original list of contacts is not changed to prevent any unexpected mistakes from occurring.
Cons: This method may have performance issues due to additional memory usage and longer time taken to overwrite the given list of contacts.
Alternative 2: Edit the current list of contacts directly by adding a function to the AddressBook class.
Pros: This method is less time and storage consuming as sorting is achieved in a single array.
Cons: There is no way to obtain the original list of contacts for other functions. If a mistake is made, the original list of contacts will be compromised. There is a need to update all classes that inherits from AddressBook class which may be confusing.

End of Extract


Enhancement Added: birthday command

External behavior


Start of Extract [from: User Guide]

Adding a birthday to selected contacts : birthday

Adds the given birthday to the specified contacts .
Format:
birthday INDEX [b/BIRTHDAY]
bd INDEX [b/BIRTHDAY]

  • Adds the birthday to the contact specified by the INDEX.

  • The index refers to the index number shown in the most recent listing.

  • The index must be a positive integer 1, 2, 3, …​

  • The birthday must be in positive intgers 1, 2, 3, …​

  • The birthday must be 6 or 8 integers long in the format DD/MM/YY or DD/MM/YYYY …​

  • The month and day of the birthday added will be populated in the calendar as a red block. More details is shown in figure 4 below.

Examples:

  • list
    birthday 1 b/21/10/95
    Adds the birthday "21 Oct 95" to the 1st contact in UniCity’s contact list.

  • bd 3 b/21/10/1995
    Adds the birthday "21 Oct 1995" to the 3rd contact in UniCity’s contact list.

birthday command ui

Figure 5: UI shown for birthday command

End of Extract


Justification

The purpose of implementing birthday was so that users can record down their friends' birthday details so that they can celebrate other friend’s birthday.
In university, birthday celebration has always been an occasion for everyone to meet up and wish the well being of the person. Hence you would not want to miss out any of these days. This birthday command allows you to keep track of birthdays of your close friends.

Implementation


Start of Extract [from: Developer Guide]

Birthday mechanism (Since v1.3)

The birthday mechanism is achieved by the AddBirthdayCommand. In order to add a birthday value to a contact, the default constructor of AddBirthdayCommand takes in the index of the contact and the birthday value to be added to the contact.

AddBirthdayCommand will use the arguments and parse to AddressBookParser. This instance is then sent to AddBirthdayCommandParser which parse the index and birthday entered. Invalid indexes and command format will be handled by throwing an exception as shown below:

public class AddBirthdayCommandParser implements Parser<BirthdayCommand> {
    public BirthdayCommand parse(String args) throws ParseException {
        try {
            // ... parse index and pass it to `BirthdayCommand`...
        } catch (IllegalValueException ive) {
            // ... throw an exception ...
        }
    }
}

The following sequence diagram shows how AddBirthdayCommand is processed:

BirthdaySequenceDiagram

Upon successfully adding of the birthday value to the contact with the given index shown in the list, it will change the value of the Birthday field of a Person.

At the same time, the Birthday class checks for the valid date entered by the user to ensure that it is in the format of DD/MM/YY or DD/MM/YYY.
As Birthday is an optional field, the default constructor of Birthday takes no arguments and set the default birthday to the Birthday field for Person. The default value to be used will be "No Birthday Added`. In some cases, BirthdayCommand needs to be initialized with a certain birthday for testing. Hence, another constructor is used to add a certain birthday to the Birthday field.

public Birthday () {
    this.birthdayNumber = DEFAULT_BIRTHDAY;
}

public Birthday(String birthday) throws IllegalValueException {
    String trimmedBirthday = birthday.trim();
    if (!isValidBirthdayFormat(trimmedBirthday)) {
        throw new
            IllegalValueException(MESSAGE_BIRTHDAY_CONSTRAINTS);
    }
    this.birthdayNumber = trimmedBirthday;
}

The AddBirthdayCommand inherits from the UndoableCommand so that users can undo the command of adding a birthday by accident. The birthday value added will be displayed in the ExtendedPersonListPanel instead of PersonCard as it is additional information for each contact.

Design Considerations

Aspect: Changing of the Birthday value of the selected Person
Alternative 1 (current choice): Copy values from all fields including the newly added birthday value to a newly created Person. Then replace this Person with the old Person in the AddressBook class.
Pros: This is easy to implement and it ensures that the original value will be intact in case any other information is changed.
Cons: Additional space is used to store the new Person instance.
Alternative 2: Edit the Birthday field in the given list of contacts directly.
Pros: No additional space is needed to store the Person instance and more straightforward.
Cons: The data can no longer be retrieved if there is any error in the process of adding birthday to the contact.

Aspect: Storing of the Birthday value of the selected Person
Alternative 1 (current choice): Add a new Birthday class.
Pros: Same coding format stored as Name, Phone and other information so the coding principle is standardized. It can also perform validation checks for the birthday value easily.
Cons: Add a new class affects many components of the code and much work needs to be done to make the changes.
Alternative 2: Use a String value to keep track of birthday for each Person.
Pros: This is easier and faster to implement.
Cons: It is prone to bugs as the String value can be overwritten easily.

End of Extract


Other contributions