Person
with Guest
and Vendor
classesGuest
class with new parametersadd
and edit
commandsfilter
commandundo
and redo
commandRsvpStatus
pie chart and DietaryRequirements
statistics panelRefer to the guide Setting up and getting started.
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
(consisting of classes Main
and MainApp
) is in charge of the app launch and shut down.
The bulk of the app's work is done by the following four components:
UI
: The UI of the App.Logic
: The command executor.Model
: Holds the data of the App in memory.Storage
: Reads data from, and writes data to, the hard disk.Commons
represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command guest delete 1
.
Each of the four main components (also shown in the diagram above),
interface
with the same name as the Component.{Component Name}Manager
class (which follows the corresponding API interface
mentioned in the previous point).For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, GuestListPanel
, VendorListPanel
, StatisticsPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the 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
The UI
component,
Logic
component.Model
data so that the UI can be updated with the modified data.Logic
component, because the UI
relies on the Logic
to execute commands.Model
component, as it displays Person
object residing in the Model
.API : Logic.java
Here's a (partial) class diagram of the Logic
component:
The sequence diagram below illustrates the interactions within the Logic
component, taking execute("guest delete 1")
API call as an example.
Note: The lifeline for GuestCommandParser
and GuestDeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
How the Logic
component works:
Logic
is called upon to execute a command, it is passed to an AddressBookParser
object which in turn creates a general parser that matches the command (e.g., GuestCommandParser
).GuestDeleteCommandParser
) and uses it to parse the command.Command
object (more precisely, an object of one of its subclasses e.g., GuestDeleteCommand
) which is executed by the LogicManager
.Model
when it is executed (e.g. to delete a guest).CommandResult
object which is returned back from Logic
.Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AddressBookParser
class creates a GuestCommandParser
or VendorCommandParser
depending on the command. This class then creates an XYZCommandParser
(XYZ
is a placeholder for the specific command name e.g., GuestAddCommandParser
) which uses the other classes shown above to parse the user command and create a XYZCommand
object (e.g., GuestAddCommand
) which the AddressBookParser
returns back as a Command
object.XYZCommandParser
classes (e.g., GuestAddCommandParser
, VendorDeleteCommandParser
, ...) inherit from the Parser
interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model
component,
Guest
objects (which are contained in a UniqueGuestList
object).Guest
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Guest>
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.UserPref
object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref
objects.Model
represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a Tag
list in the AddressBook
, which Person
references. This allows AddressBook
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.
API : Storage.java
The Storage
component,
AddressBookStorage
and UserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed).Model
component (because the Storage
component's job is to save/retrieve objects that belong to the Model
)Classes used by multiple components are in the wedlog.addressbook.commons
package.
This section describes some noteworthy details on how certain features are implemented.
The AddressBook
component stores the list of guests and vendors in the UniqueGuestList
and UniqueVendorList
classes respectively. These classes extend UniquePersonList
, which is a generic class that stores a list of Person
objects. Person
is a class that represents a person in the address book. It has two subclasses, Guest
and Vendor
, which represent a guest and a vendor respectively. Guest
has additional fields of RsvpStatus
, DietaryRequirement
and TableNumber
objects.
Furthermore, all fields except Name
in Person
and its subclasses are wrapped in an Optional
. This allows for attributes to be optional, allowing for greater flexibility.
A RsvpStatus
object has one of three possible values stored as a String: "yes", "no", and "unknown". The default value of a RsvpStatus
is "unknown".
Like Tag
, a Guest
can store multiple DietaryRequirement
objects. As such, it is optional by nature.
A TableNumber
object stores a table number as an integer. It is wrapped in an Optional
as well.
Aspect: How to store guests and vendors
The add feature allows users to add new guests or vendors with the compulsory field Name
, along with any of the optional
fields mentioned in the Tracking of Guests and Vendors section. The feature is implemented through the
classes GuestAddCommand
and VendorAddCommand
. The implementation of the various classes facilitating the add feature
on Guest
and Vendor
objects differ only in specifics that are not relevant here, so the keywords Guest
and Vendor
will be
replaced by XYZ
(e.g. XYZAddCommand
can be substituted with both GuestAddCommand
and VendorAddCommand
).
Given below is an example usage scenario and how the add mechanism behaves at each step. You may also refer to the sequence diagrams provided for a visual representation of the process.
Step 1. The user launches the application. The VersionedAddressBook
will be initialized with the initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executes xyz add n/Annette t/friend
, where xyz
is either guest
or vendor
. This allows the user to add
a guest or vendor with the name Annette
and tag friend
.
Step 3. AddressBookParser
parses the xyz
keyword and creates the XYZCommandParser
.
XYZCommandParser
parses the add
keyword and creates a XYZAddCommandParser
object. It also calls XYZAddCommandParser#parse
to parse the inputted fields.
Step 4. #parse
calls upon ParserUtil#parseABC
, where ABC
is the field being added, to check the validity of the
user input and convert it into field objects (e.g. string representing a new name into a Name
object).
#parse
then creates an XYZAddCommand
using the created field objects.
Step 5. Lastly, XYZAddCommand#execute
adds a XYZ
with the given values to the UniqueXYZList
.
The delete
feature allows users to delete a guest or vendor in WedLog, through the respective classes GuestDeleteCommand
and VendorDeleteCommand
. Note that the implementation of GuestDeleteCommand
and VendorDeleteCommand
is identical and will be referred to as XYZDeleteCommand
. The feature makes use of the current Index
of the person in the displayed list to identify the person.
Given below is an example usage scenario and how the delete
mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook
will be initialized with the initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executed xyz filter r/no
, where xyz
is either guest
or vendor
, to show either guests or vendors with the RSVP Status
set to no
.
Step 3. The user executes xyz delete 1
, to delete the first guest or vendor in the currently displayed list.
Step 4. XYZDeleteCommandParser
parses the Index
to create a XYZDeleteCommand
. The following sequence diagram shows how the parsing of a delete command works:
Step 5. The resulting XYZDeleteCommand
is then executed by the Logic Manager
.
The following sequence diagram shows how the execution of a delete command works:
Aspect: How to specify a guest or vendor using Index
Index
refers to the index on the full list.
Index
refers to the index on the currently displayed list.
The filter
feature allows the user to view a filtered list for both guests and vendors, through the respective classes VendorFilterCommand
and GuestFilterCommand
.
The filtering is based on an All-Field-Match search (e.g. guest filter n/John r/yes
will show only guests that have "John" in their name and have also agreed to come to the wedding).
The strings separated by spaces in the field of the person have to exactly match the keywords provided in the filter command parameters (e.g. guest filter n/John
will return a guest by the
name of John Doe
, however a guest with the name Johnathan
will not be returned.
The implementation of the various classes facilitating the filter feature on Guest and Vendor objects differ only in specifics that are not relevant here, so the keywords Guest and Vendor will be replaced by XYZ
(e.g. XYZFilterCommand can be substituted with both GuestFilterCommand and VendorFilterCommand).
Given below is an example usage scenario for filtering guests and how the filter mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook
will be initialized with the initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executes XYZ add n/John doe …
to add a new person.
Step 3. The user executes XYZ add n/Johnathan …
to add another new person.
Step 4. The user executes XYZ filter n/John
to filter out names that contain the keyword "John". The execution of this XYZFilterCommand
updates the filteredXYZs
list via the updateFilteredXYZList
method.
Step 5. A list view of only the XYZ named John is returned.
Note: The XYZ with name "Johnathan" is not returned due to the words in the name not matching the keyword "John" However, a XYZ with name "John doe" would be returned as his name contains the keyword "John".
The filtering logic is done with predicate classes that implement Java's Predicate interface:
Both filteredGuests
and filteredVendors
lists can be filtered by predicates of PersonPredicate
type, However only filteredGuests
list can be filtered by predicates of GuestPredicates
type.
The predicates allowed to filter the respective lists will be referred to as ABCPredicate
for generalisability.
The following sequence diagrams shows how the filter
command works:
When a user enters XYZ filter n/John a/jurong west st 65
, the XYZFilterCommandParser
created will parse the parameters in the command.
For each valid parameter, it creates the respective ABCPredicate. In the example command, there are two search criteria
corresponding to name and address, hence a NamePredicate
and a AddressPredicate
is created.
These predicates are stored in a List
and passed to the XYZFilterCommand
constructor. the predicates are then stored
in the XYZFilterCommand
object and awaits execution.
Upon execution of the XYZFilterCommand
, it updates the model by having the predicates passed into the preparePredicate
internal method. The list of predicates is then made into 1 overall predicate which checks if the list of predicates are
all true. If they are, the overall predicate returns true, else false. This is done through the usage of Stream
.
The resulting predicate is a Predicate<XYZ>
.
The model's filteredXYZs
list is then updated by passing in the resultant predicate into setPredicate
method.
Finally, the filtered list is displayed.
Aspect: Filtering fields by All-Fields-Match or Partial-Fields-Match relationship
Aspect: Filter by Tag or String
The edit feature allows users to edit the parameters of existing guests or vendors in WedLog, through the respective classes GuestEditCommand
and VendorEditCommand
. Note that the implementation of GuestEditCommand
and VendorEditCommand
is identical and will be referred to as XYZEditCommand
. The feature uses the current Index
of the person in the displayed list to identify the person.
Given below is an example usage scenario of GuestEditCommand
and how the operation behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook
will be initialized with the initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executes guest filter n/John
to show only guests with the name John
.
Step 3. The user executes guest edit 2 p/
to edit the 2nd guest in the current list to have no phone number.
Step 4. GuestEditCommandParser
parses the Index
and the additional arguments to create an GuestEditCommand
. The following sequence diagram shows how the parsing of an edit command works:
Note: The lifeline for GuestCommandParser
, GuestEditCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Step 5. The resulting GuestEditCommand
object is then executed by the LogicManager
. The following sequence diagram shows how the execution of an edit command works:
Note: The lifeline for GuestEditCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Aspect: How EditXYZDescriptor
works:
The EditXYZDescriptor
describes if the XYZ
fields should be modified, deleted, or left alone.
Alternative 1 (current choice):
XYZ
, create two fields field
and isFieldEdited
in EditXYZDesriptor
, e.g. phone
and isPhoneEdited
.isFieldEdited
is true
and field
is null
.Alternative 2:
EditPhone
, which would capture the different states.The undo/redo mechanism is facilitated by VersionedAddressBook
. It extends AddressBook
with an undo/redo history, stored internally as an addressBookStateList
and currentStatePointer
. Additionally, it implements the following operations:
VersionedAddressBook#commit()
— Saves the current address book state in its history.VersionedAddressBook#undo()
— Restores the previous address book state from its history.VersionedAddressBook#redo()
— Restores a previously undone address book state from its history.These operations are exposed in the Model
interface as Model#commitAddressBook()
, Model#undoAddressBook()
and Model#redoAddressBook()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedAddressBook
will be initialized with the initial address book state, and the currentStatePointer
pointing to that single address book state.
Step 2. The user executes delete 5
command to delete the 5th person in the address book. The delete
command calls Model#commitAddressBook()
, causing the modified state of the address book after the delete 5
command executes to be saved in the addressBookStateList
, and the currentStatePointer
is shifted to the newly inserted address book state.
Step 3. The user executes add n/David …
to add a new person. The add
command also calls Model#commitAddressBook()
, causing another modified address book state to be saved into the addressBookStateList
.
Note: If a command fails its execution, it will not call Model#commitAddressBook()
, so the address book state will not be saved into the addressBookStateList
.
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo
command. The undo
command will call Model#undoAddressBook()
, which will shift the currentStatePointer
once to the left, pointing it to the previous address book state, and restores the address book to that state.
Note: If the currentStatePointer
is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The undo
command uses Model#canUndoAddressBook()
to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
The following sequence diagram shows how the undo operation works:
Note: The lifeline for UndoCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The redo
command does the opposite — it calls Model#redoAddressBook()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the address book to that state.
Note: If the currentStatePointer
is at index addressBookStateList.size() - 1
, pointing to the latest address book state, then there are no undone AddressBook states to restore. The redo
command uses Model#canRedoAddressBook()
to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
Step 5. The user then decides to execute the command list
. Commands that do not modify the address book, such as list
, will usually not call Model#commitAddressBook()
, Model#undoAddressBook()
or Model#redoAddressBook()
. Thus, the addressBookStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitAddressBook()
. Since the currentStatePointer
is not pointing at the end of the addressBookStateList
, all address book states after the currentStatePointer
will be purged. Reason: It no longer makes sense to redo the add n/David …
command. This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
Aspect: How undo & redo executes:
Alternative 1 (current choice): Saves the entire address book.
Alternative 2: Individual command knows how to undo/redo by itself.
delete
, just save the person being deleted).Target user profile: A bride or groom who
Value proposition: consolidate all information related to wedding guests and vendors into 1 platform for streamlined planning.
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * | new user | add new guests with name and contact | keep track of the people whom I invited to the wedding |
* * * | new user | remove existing guests | remove guests I erroneously added |
* * * | new user | record down dietary requirements for guests | cater correct types of meals for my guests |
* * * | new user | update RSVP status of a guest | track who is coming |
* * * | new user | save data into local storage | keep my data even after I exit the app |
* * * | new user | retrieve data from local storage | access past data that I have inputted |
* * * | user liaising with many vendors | add new vendor with name and contact | keep track of which vendors I am currently in contact with |
* * * | user liaising with many vendors | remove existing vendors | remove vendors I erroneously added |
* * | user with many guests | view how many guests have RSVP'd | know how many guests are confirmed to be coming |
* * | user with many guests | view a specific guest's details | understand the arrangements I've made for a particular guest |
* * | user with many guests | view the total number of each type of diet | cater the appropriate number and types of meals |
* * | user with many guests | filter guests with dietary restrictions | cater alternate meals for them |
* * | user with many guests | assign a guest to a table number | keep track of seating arrangements |
* * | user with many guests | filter guests by table | see who is sitting at each table |
* * | user with many guests | add guests to a group | know which group a guest belongs to |
* * | user with many guests | filter guests by groups (eg family, friends) | access and manage relevant information for each group |
* | financially savvy user | track my total expenses | stay within budget |
* | financially savvy user | keep track of the costs associated with each vendor | track how much I have spent on the wedding |
* | financially savvy user | record gift registry | take note of which gifts are already bought, and by who |
* | financially savvy user | keep track of red packets received from guests | keep future references on gift exchange |
* | financially savvy user | view total amount I collected from wedding presents | know how much cash I have |
* | user finding a wedding location | record pros and cons of possible locations | choose the best location |
* | task-oriented user | add tasks and track roadmap | keep track of the wedding planning progress |
* | task-oriented user | get reminders to do tasks when deadlines are nearing | not miss important deadlines |
* | task-oriented user | assign tasks and deadlines to guests | keep track of when I need to follow-up with them |
* | task-oriented user | assign tasks and deadlines to vendors | keep track of when I need to follow-up with them |
* | task-oriented user | view all the deadlines that have passed | identify the actions that I need to prioritise |
* | task-oriented user | view countdown to wedding | know the time I have left till the wedding |
* | user planning my reception | plan the flow of events during the reception | know when to do what |
* | experienced user | view most recent commands | look back on what was recorded previously |
* | experienced user | undo the last command | undo accidental or erroneous commands |
* | experienced user | import data from a csv file format onto this platform | easily transfer existing information from other sources |
* | experienced user | export data into an excel format | easily send data to vendors |
* | experienced user | share my address book with another user | plan the wedding together with my partner |
* | experienced user | add custom fields for guests | keep track of miscellaneous information specific to my wedding |
(For all use cases below, the System is WedLog
and the Actor is the user
, unless specified otherwise)
Use case: UC1 - Add a guest
MSS:
Extensions:
1a. The given input format is invalid.
1a1. WedLog shows an error message.
1a2. User provides guest details in a different format.
Steps 1a1-1a2 are repeated until the User input format is valid.
Use case resumes from step 2.
1b. The guest already exists in the guest list.
1b1. WedLog shows an error message.
Use case ends.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC2 - Add a vendor
MSS:
Extensions:
1a. The given input format is invalid.
1a1. WedLog shows an error message.
1a2. User provides vendor details in a different format.
Steps 1a1-1a2 are repeated until the User input format is valid.
Use case resumes from step 2.
1b. The vendor already exists in the vendor list.
1b1. WedLog shows an error message.
Use case ends.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC3 - View all guests
MSS:
Extensions:
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC4 - View all vendors
MSS:
Extensions:
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC5 - Delete a guest
MSS:
Extensions:
3a. The given index is invalid.
3a1. WedLog shows an error message.
3a2. User requests to delete the guest using a different index.
Steps 3a1-3a2 are repeated until the User provides a valid index.
Use case resumes from step 4.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC6 - Delete a vendor
MSS:
Extensions:
3a. The given index is invalid.
3a1. WedLog shows an error message.
3a2. User requests to delete the vendor using a different index.
Steps 3a1-3a2 are repeated until the User provides a valid index.
Use case resumes from step 4.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC7 - Filter guests
MSS:
Extensions:
3a. The given field input is invalid.
3a1. WedLog shows an error message.
3a2. User requests to use a different input.
Steps 3a1-3a2 are repeated until the User provides a valid input.
Use case resumes from step 4.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC8 - Filter vendors
MSS:
Extensions:
3a. The given field input is invalid.
3a1. WedLog shows an error message.
3a2. User requests to use a different input.
Steps 3a1-3a2 are repeated until the User provides a valid input.
Use case resumes from step 4.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC9 - Edit a guest
MSS:
Extensions:
3a. The given index is invalid.
3a1. WedLog shows an error message.
3a2. User requests to delete the vendor using a different index.
Steps 3a1-3a2 are repeated until the User provides a valid index.
Use case resumes from step 4.
3b. The given field input is invalid.
3b1. WedLog shows an error message.
3b2. User requests to use a different input.
Steps 3b1-3b2 are repeated until the User provides a valid input.
Use case resumes from step 4.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
Use case: UC10 - Edit a vendor
MSS:
Extensions:
3a. The given index is invalid.
3a1. WedLog shows an error message.
3a2. User requests to delete the vendor using a different index.
Steps 3a1-3a2 are repeated until the User provides a valid index.
Use case resumes from step 4.
3b. The given field input is invalid.
3b1. WedLog shows an error message.
3b2. User requests to use a different input.
Steps 3b1-3b2 are repeated until the User provides a valid input.
Use case resumes from step 4.
*a. At any time, user inputs an invalid command/syntax.
*a1. WedLog shows an error message.
11
or above installed.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
Download the .jar
file and copy into an empty folder
Double-click the .jar
file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
Saving window preferences
Resize the window to an optimum size. Move the window to a different location. Close the window.
Re-launch the app by double-clicking the .jar
file.
Expected: The most recent window size and location is retained.
Prerequisites: Before launching the application, open the data
folder.
Delete the data/addressbook.json
file
Expected: Upon app launch, the app is populated with sample data.
Delete the data
folder
Expected: Upon app launch, the app is populated with sample data.
Corrupt the data/addressbook.json
file
Expected: Upon app launch, the app has no guests or vendors populated.
Adding a guest: guest add n/John Doe
Expected: Guest with the name John Doe
is added.
Adding a guest without a name: guest add e/johndoe@example.com
Expected: No guest is added, and an error message is shown.
Adding a guest with an invalid RSVP status: guest add n/John Doe r/invalid
Expected: No guest is added, and an error message is shown.
Prerequisites: List all guests using the guest list
command. There should be at least 3, but less than 10,000 guests in the list.
Deleting a guest: guest delete 3
Expected: The third guest is removed from the list.
Deleting a guest that does not exist: guest delete 10000
Expected: No guest is deleted, and an error message is shown.
Deleting a guest with an invalid index: guest delete 0
Expected: No guest is deleted, and an error message is shown.
Prerequisites: List all guests using the guest list
command. There should be at least 3, but less than 10,000 guests in the list.
Editing a guest: guest edit 2 p/68423611
Expected: The second guest in the list has their phone number updated to 68423611
.
Editing multiple fields of a guest: guest edit 3 tn/2 r/yes
Expected: The third guest in the list has their table number updated to 2
and their RSVP status to yes
.
Editing a guest with invalid name: guest edit 3 n/!nvalid N@me
Expected: No guest is edited, and an error message is shown.
Editing a guest without specifying any edits: guest edit 2
Expected: No guest is edited, and an error message is shown.
Editing a guest that does not exist: guest edit 10000
Expected: No guest is edited, and an error message is shown.
Prerequisites: There should be multiple guests in the list.
Filter guests by tag: guest filter t/friends
Expected: Only guests with the tag friends
should be shown.
Filter guests by multiple tags: guest filter t/friends t/colleagues
Expected: Only guests with both tags friends
and colleagues
should be shown.
Filter guests without specifying fields: guest filter
Expected: The vendor list remains unchanged, and an error message is shown.
Adding a vendor: vendor add n/John Doe
Expected: Vendor with the name John Doe
is added.
Adding a vendor without a name: vendor add e/johndoe@example.com
Expected: No vendor is added, and an error message is shown.
Adding a vendor with an invalid email: vendor add n/John e/invalidemail
Expected: No vendor is added, and an error message is shown.
Prerequisites: List all vendors using the vendor list
command. There should be at least 3, but less than 10,000 vendors in the list.
Deleting a vendor: vendor delete 3
Expected: The third vendor is removed from the list.
Deleting a vendor that does not exist: vendor delete 10000
Expected: No vendor is deleted, and an error message is shown.
Deleting a vendor with an invalid index: vendor delete 0
Expected: No vendor is deleted, and an error message is shown.
Prerequisites: List all vendors using the vendor list
command. There should be at least 3, but less than 10,000 vendors in the list.
Editing a vendor: vendor edit 2 p/68423611
Expected: The second vendor in the list has their phone number updated to 68423611
.
Editing multiple fields of a vendor: vendor edit 3 p/66846122 e/daisypetals@example.com
Expected: The third vendor in the list has their phone number updated to 66846122
and their email address to daisypetals@example.com
.
Editing a vendor with invalid name: vendor edit 3 n/!nvalid N@me
Expected: No vendor is edited, and an error message is shown.
Editing a vendor without specifying any edits: vendor edit 2
Expected: No vendor is edited, and an error message is shown.
Editing a vendor that does not exist: vendor edit 10000
Expected: No vendor is edited, and an error message is shown.
Prerequisites: There should be multiple vendors in the list.
Filter vendors by tag: vendor filter t/catering
Expected: Only vendors with the tag catering
should be shown.
Filter vendors by multiple tags: vendor filter t/catering t/venue
Expected: Only vendors with both tags catering
and venue
should be shown.
Filter vendors without specifying fields: vendor filter
Expected: The vendor list remains unchanged, and an error message is shown.
Prerequisites: There should be at least one guest or vendor in the application.
Clearing guests and vendors: clear
Expected: All guests and vendors are deleted.
Clearing guests and vendors with extra input: clear extra
Expected: All guests and vendors are deleted.
Given below are the planned enhancements for WedLog, beyond v1.4. This list is not ranked in order of importance.
Currently, WedLog only allows names of guests and vendors to be alphanumeric. However, this may not be ideal as some names may contain special characters such as hyphens, apostrophes, and spaces. For example, the name "Mary-Ann O'Neil" is currently not allowed. This enhancement will allow such names to be added to WedLog.
We understand that some names may contain special characters. This enhancement will allow users to add names of guests and vendors that contain special characters. This will allow WedLog to be more flexible in terms of the names that can be added to it.
The implementation of this enhancement will be done in the Name
class. By changing the validation regex of a name to allow special characters, users can input special characters in the names
of guests and vendors.
Currently, upon the input of a wrong command, WedLog displays rather general error messages to the user. For example, if I type: guest add name/...
instead of guest add n/...
,
the error message shown is Invalid command format! ...
. This is not very helpful to the user as it does not tell the user what is wrong with the command. This enhancement will allow WedLog to
display more specific error messages to the user, such as Invalid command format! The prefix 'name/' is not recognised.
, for example.
We understand that due to the number of possible command labels available, users may not be able to remember all of them. This enhancement will allow users to know exactly what is wrong with their command, and thus allow them to rectify their mistakes more easily.
The implementation of this enhancement will be done in the individual parse()
methods in each command parser class. By checking each command label for validity, we can display more specific
error messages to the user.
Currently, WedLog only allows users to track one phone number per guest or vendor. The restriction imposed on phone number inputs are that it has to be a (1) a number input, (2) cannot contain special characters, and (3) must be at least 3 digits long. This does not allow users to track contacts with multiple phone numbers. This enhancement will allow users to track multiple phone numbers for each guest or vendor, and differentiate between them.
We understand that our users may want to track guests or vendors with multiple phone numbers. A possible format multiple phone number representation
would be 12345678 (HP) 61235938 (O)
. This allows each guest and vendor to have multiple phone numbers tracked, and also allows users to differentiate between them.
This will allow WedLog to be more flexible in terms of the phone numbers that can be tracked.
The implementation of this enhancement can be done in one of two ways.
Phone
to follow the implementation of Tag
and DietaryRequirement
. A Person
superclass would then have a set of Phone
objects, i.e. Set<Phone>
.
A Phone
object would also need to keep track of an identifier, e.g. '(HP)' or '(O)', to allow differentiation between different phone numbers.Phone
to accept other non-numerical values in the input. This allows the user to flexibly add identifiers such as '(HP)' or '(O)' to differentiate between
different phone numbers.Currently, long data fields in WedLog are not line-wrapped in the UI. This causes information to be displayed in a single continuous line. This can lead to information being cut off when the data stored is too long.
This enhancement will allow text wrapping for long data fields in WedLog.
Although the current UI of WedLog should contain most typical data fields without overflowing, there may be cases where the data fields are too long. This enhancement will allow users to input extremely long data fields without the information being cut off.
In the UI files, change the .fxml
files to allow text wrapping for long data fields. This can be done by adding the wrapText="true"
attribute to the relevant Label
elements.
We have identified 2 main issues with the use of the current JavaFX pie chart in WedLog.
This enhancement will improve the pie chart in WedLog by fixing these 2 issues.
As a cosmetic enhancement, this will improve the overall look of the pie chart in WedLog. By ensuring labels appear when they need to and not appear when they should not, this will allow users to better understand the pie chart, improving accessibility.
The way we populate the pie chart data is by traversing the list of guests and allocating each pie chart slice with the RSVP status of each guest in order. Since we want to maintain a specific colour scheme for the chart slices, we have to ensure that the order of slices is maintained. This can lead to unexpected behaviour such as the floating label appearing when there are not yet guests with RSVP status "no". In JavaFX, in order to change the styling of the pie chart dynamically, we will need to change its style attributes in the controller class after the scene has been shown. However, the current implementation of updating UI elements is done by removing existing components and re-rendering components when the data changes, i.e. after a command is executed. In particular, the pie chart is deleted and a new one is created based on the updated data. This means that it is not possible to conditionally style the chart slices within the current implementation.
One way to fix this issue is to change the way UI elements are updated. Instead of deleting and re-rendering components, we can update the existing components with the new data. This is a non-trivial implementation and will require a rework of the UI code. This enhancement will then address the issues of (1) labels appearing when they should not, and (2) labels disappearing when they should not.
Currently, tags are case-sensitive in WedLog. This means that if a user adds a tag with the same name but different case, e.g. 'family' and 'Family', WedLog will treat them as different tags. This can lead to duplicate tags being added to WedLog, making it confusing for users.
This enhancement will allow WedLog to detect duplicate tags, regardless of case. A tag will be stored in WedLog in lowercase, for standardisation.
We understand that our users may assign tags with the same name but different case. This enhancement will enforce case-insensitivity for the input of tags to prevent duplicate tags from being added to WedLog.
The implementation of this enhancement will be done in the Tag
class. By storing tags in lowercase, we can ensure that duplicate tags
are detected by means of string equality, and handled accordingly.
Currently, dietary requirements are case-sensitive in WedLog. This means that if a user adds a dietary requirement with the same name but different case, e.g. 'vegan' and 'Vegan', WedLog will treat them as different dietary requirements. This can lead to duplicate dietary requirements being added to WedLog, making it confusing for users.
This enhancement will allow WedLog to detect duplicate dietary requirements, regardless of case. A dietary requirement will be stored in WedLog in lowercase, for standardisation.
We understand that our users may assign dietary requirements with the same name but different case. This enhancement will enforce case-insensitivity for the input of dietary requirements, to prevent duplicate dietary requirements from being added to WedLog.
The implementation of this enhancement will be done in the DietaryRequirement
class. By storing dietary requirements in lowercase, we can ensure that duplicate
dietary requirements are detected by means of string equality, and handled accordingly.
We noted issues of the command result display box being too small, making it hard for users to view the results of their commands.
This enhancement will allow users to resize all panels in WedLog, including the command result display box.
Having the ability to resize individual components will allow users to customise the UI to their needs and liking. This will improve the overall user experience of WedLog, because information will less likely be restricted by the size of other components.
The implementation of this enhancement will be done in the .fxml
UI files. On top of making the entire window resizable, we will also need to make individual components resizable.
This can be done by adding the resizable="true"
attribute to the relevant Pane
elements, and setting the minimum and maximum bounds of each component.
We are aware of the issue that some macOS users have with the help window. When the app is running in full-screen mode and the help window is launched, it is also launched in full-screen mode, as a separate window.
This can cause some confusion for users as they may not know how to exit the help window, or navigate back to the main window of WedLog. It also does not make sense for the help window to be maximised as such. This enhancement will improve the user experience of macOS users by removing the full-screen support for the help window.
By restricting the help window to its intended size (big enough to display the UG URL and Copy URL
button), this will allow users to navigate the help window more easily.
The implementation of this enhancement will be done in the HelpWindow
class. By removing the full-screen support for the help window, we can ensure that the help window is restricted to
its intended size.
This issue does not occur in other operating systems such as Windows and Linux. This enhancement will only affect macOS users.
The current colour scheme of WedLog has raised some concerns of accessibility.
This enhancement will improve the colour scheme of WedLog to make it more accessible by increasing the colour contrast between UI components.
Improving the colour scheme will increase colour contrast between certain affected UI components, making it easier for users to read the information displayed. This will improve the overall user experience of WedLog.
The implementation of this enhancement will be done by first designing a different colour scheme with higher contrast for WedLog, and then changing the colour scheme of the UI components
by changing the relevant style attributes in the .css
files.
This section documents the effort required to evolve AB3 into WedLog.
Person
with Guest
and Vendor
classesThis involved:
Guest
and Vendor
classes.Person
to handle Guest
and Vendor
.
EditCommand
into GuestEditCommand
and VendorEditCommand
.GuestCommandParser
and VendorCommandParser
.Person
class.This was time and effort intensive as:
Guest
and Vendor
separately.Our app allows fields like Phone
, Email
, Address
and more to be empty, which AB3 did not.
This increased complexity of our application as features like add
, edit
and filter
had to account for more
variations in values.
Guest
class with new parametersWe enhanced the Guest
class to track additional information not covered in the original Person
class. This involved:
TableNumber
, RsvpStatus
and DietaryRequirement
classes and integrating them into existing
features like add
and edit
.This change was challenging as it required lots of in-depth design discussions on how to best represent the information.
RsvpStatus
class: We debated on the appropriate amount of flexibility to give users, and eventually
settled on restricting acceptable values for RsvpStatus
to Yes
, No
, and Unknown
.DietaryRequirement
class: We initially stored the information as a string, but later adapted it into a
tag system to facilitate UI design and filtering.add
and edit
commandsWe enhanced the add
and edit
commands to accept and interpret empty parameters. This involved:
p/
will delete the existing Phone
value, while an empty r/
will update
RsvpStatus
to Unknown
.filter
commandThis involved creating a new command not available in AB3.
Implementing this was challenging:
find
command which searched only the Name
field, our filter
command is able to filter
via every field in Guest
and Vendor
.undo
and redo
commandThis involved:
undo
and redo
respectively.This involved creating a new UI design and logic that was not available in AB3.
This was challenging and time-consuming as:
RsvpStatistics
and DietaryRequirementStatistics
classes.DietaryRequirementStatistics
, we had to design an algorithm to capture the different unique dietary requirements and their respective occurrences.