xiaoyu nus

Role: Developer
Responsibilities: Reminder System + Logo and UI Designer


PROJECT: Xpire

Overview

My team of 5 computer science students have been given the task of morphing a command line interface(CLI) application named AddressBook into a brand new app. Being students staying on campus in National University of Singapore, as we are keen to solve the issue of food wastage due to them passing their expiry date. As such, we have created the app Xpire to help students track the expiry dates of items. Our app is equipped with many functions like reminder, search and sort. The application is written in Java over 3 months, and has about 15 kLoC.

Summary of contributions

  • Major enhancement: added the reminder system

    • Purpose: to allow user to customise a reminder date, starting form which the item needs to be reminded of its expiry date.

    • Importance: As items last for different duration before which they expires, customising the reminder eases the user’s mind as he or she does not have to remember when is the item supposed to be consumed or replaced.

    • Highlights: The reminder is enhanced by a filter to list down all items in alerting condition. It can also filter items based on number of days left before their expiration date. As such, the complexity of the implementation is high, requiring mastery knowledge of many components including the Module, User Interface as well as Logic. The feature works with existing and also future commands, and can be turned into active notification readily.

  • Major enhancement: redesigned graphic user interface(GUI)

    • Purpose: to make the GUI one that specifically serves Xpire and no other purposes by displaying the number of days left before an item expires and changes its colour accordingly.

    • Importance: to make our application different from a notebook or to-do list on paper, it is important that the information regarding the item dynamically changes according to its status so that the user can easily identify expiring items and handle them properly.

    • Highlights: Despite limited resources on the use of JavaFX, the overall effect achieves high degree of comfort and convenience. The task is especially challenging as the UI components interacts with many other modules such as the lists of items, the feedback and the commands entered. The feature is not hard coded and can easily integrate with future commands.

  • Minor enhancement: added a command history which allows the user to navigate to previous commands using up/down keys.

  • Minor enhancement: added the all items panel which displays a static view of all items in both tracking list and to-buy list.

  • Minor enhancement: enabled a clickable hyperlink to our User Guide page.

  • Minor enhancement: set the upper and lower bonds for expiry date and reminder threshold to prevent unwanted bugs.

  • Minor enhancement: set a restriction on the input command length through the UI to prevent String overflow.

  • Code contributed: [RepoSense]

  • Other contributions:

    • Team tasks:

      • Refactor UI components from the AddressBook. (Pull requests #48)

      • Designed the logo. (Pull request #77)

      • Designed the mock-up UI.

    • Documentation:

      • Added GUI and User Guide writing instructions of the User Guide: (Pull requests #134)

    • Enhancements to existing features:

      • Refactored and expanded TypicalItems to be used by J-Unit Testing. (Pull requests #219)

      • Make the ResultDisplay resizable. (Pull requests #184)

Contributions to the User Guide

You can refer to parts of my changes to the User Guide below, including some GUI components and reminder components.

Retrieve Previous Entry

Just like any other Command Line App, you can easily retrieve your previous commands or go back to later commands using the and keys on your keyboard. You can call back up to 20 commands you entered.

Setting reminder for an item: set reminder

Adding a reminder some days before an item’s expiry date
set reminder
Figure 1. Reminder set for item at index 4

Sets a reminder for your item.
Format: set reminder|<index>|<reminder threshold>

Set reminder is designed for you to customise when you want to be alerted of an item’s condition. In the above example, reminder threshold refers to the number of days before the item’s expiry date. The reminder for an item will be activated when the number of days left before an item’s expiry date is less than or equal to the reminder threshold. In other words, by setting the reminder threshold of an item to n days, you start to be reminded of this items n days before its expiry date.

To reduce disturbance, the app does not pop up notifications. Instead, you will be reminded through the alerting yellow colour of the item whose reminder has been activated in the View list. You can also view all items with active reminder through the check command. (Refer to the following section.)

Examples:

  • set reminder|2|4
    Sets a reminder for the second item in the list 4 days before its expiry date.

Removing the reminder for an item

You can remove the reminder for your item by resetting it to the default value 0. Format: set reminder|<index>|0

Examples:

  • set reminder|1|0
    Removes the reminder for the first item in the list.

  • All items have their default reminder threshold set to 0.

  • Reminder cannot be set on already expired items.

  • A reminder cannot be set to be before the current date. For example, if the current date is 20/9/2019 , it is not possible to set the reminder on 19/9/2019 by entering a reminder threshold greater than the item’s number of days left. However, the app understands that you want the reminder to be activated immediately, and will activate the reminder right away.

  • The maximum reminder threshold is 36500 days.

Contributions to the Developer Guide

The following section are parts of my changes to the Developer Guide. Hope you can understands my features from a more technical point of view.

UI component

UiComponentClassDiagram
Figure 2. Structure of the UI Component

Reminders for expiring items

The reminder function comprises two parts. Firstly, user sets a date designated to active the reminder through the command set reminder. Then, user will be able to find all items whose reminder has been activated at present through the command check.
There is also an enhanced function which allows the user to filter items expiring within a specified number of days, through the check|<days> command.

Implementation

Set reminder

The set reminder function is implemented in a similar way as delete, add and tag. It is facilitated by the method setItem in Model where the old item in Xpire will be replaced by a new item with an updated value for the field ReminderThreshold. It is activated using the command set reminder.

You can refer to the example usage scenario given below to see what happens at each stage of the execution.

Scenario: the user wants to set a reminder for an item with index 1 in the current view of the list 1 day before its expiry date.

Step 1: the user input is parsed by SetReminderCommandParser to check validity of the reminder threshold.

Step 2: the SetReminderCommandParser creates a SetReminderCommand object if the input is valid. The SetReminderCommand contains a new ReminderThreshold object. The SetReminderCommand is returned to the LogicManager and executed.

Step 3: during the execution, a copy of the old item with the new ReminderThreshold will be created. The copy will replace the old one in the Xpire by ModelManager.

Step 4: result of execution will be displayed.

The following sequence diagram shows how the operation works:

SetReminderUML
Figure 3. SetReminderSequenceDiagram
Check

The basic check function uses the updateFilteredItemList method provided by model to filter items whose reminder has been activated. The predicate used by the filtering method is named ReminderThresholdExceededPredicate.

The ReminderThresholdExceededPredicate will check whether the number of days to an item’s expiry date is smaller than or equal to its reminder threshold.

You can see how the Check operation works in the following sequence diagram.

CheckCommandNoArgUML
Figure 4. CheckSequenceDiagram

A successful check will lists all items marked as yellow and red int he ViewPanel of the UI component.

Check with days

The enhanced check function also uses the updateFilteredItemList method provided by model to filter items. The condition for filtering is that the user input number of days is smaller than or equal to the number of days to an item’s expiry date. This is done by the predicate named ExpiringSoonPredicate.

You can see how the Check|<days> operation works in the following sequence diagram.

CheckCommandArgUML
Figure 5. CheckDaysSequenceDiagram

Design Considerations

Aspect: How set reminder executes
  • Alternative 1 (current choice): Set new item to replace the original one in Xpire

    • Pros: removes unwanted dependency as modifying the item directly in SetReminderCommand class requires the original XpireItemList to be passed to the class and could possibly result in unwanted modification. Using a ObservableList instead prevents any changes to the item by the SetReminderCommand class.

    • Cons: Time complexity is O(nlogn). Despite setting a reminder will not result in change in name or expiry date of the item, and thus requires no change to the sorted list, the list will still be sorted as a new item is considered added to the list.

  • Alternative 2: Modify the original item

    • Pros: Time complexity is low: O(n) to locate the item.

    • Cons: This is dangerous as modifying items in a sorted list is prone to unwanted side effects and undesirable modifications. === User Interface The UI contains two panels that change according to the items in the XpireItemList and ReplenishList. However, these UI components are not able to update by listening to changes in these ObservableLists. This is because both lists are sorted and thus all items in the lists will be modified each time a sort, add, delete, tag or other commands that modify the lists are executed, causing the listener in the API to catch unwanted changes. Instead, the lists are passed as parameters to the UI classes through MainWindow and rendered each time a command is executed.

As as an example of how the UI were implemented, we will examine the implementation of ViewPanel.

The View Panel

ViewPanel is a container for many ItemCards, each carrying information about the items.
Given below are the steps of an example scenario of how ViewPanel is constructed and updated:

  1. The User launches the application and the MainWindow creates a new ViewPanelPlaceholder container that hosts the ViewPanel.

  2. MainWindow calls Logic which in turn calls Model to obtain a current active list through getCurrentFilteredItemList(). Depending on the user’s current list in view, it will either be an XpireItemList or ReplenishList.

  3. On starting of the GUI, MainWindow makes a call to fillInnerParts() , where the MainWindow passes the list as parameters to the constructor of the ViewPanel.

  4. ViewPanel makes a call to displayItems(ObservableList) and constructs a Collection of ItemCard by mapping each XpireItem or Item to an ItemCard . .ItemCard takes as parameters the item and its index in the list. It renders all fields of an XpireItem and Item and also dose an additional check on the condition of the XpireItem and assign it to different colours respectively through setColour().

  5. The app then starts.

Let’s now see what happens when a command is executed.

If the command is a help, exit of export, the ViewPanel will not be updated and refreshed.
  1. In MainWindow, a call to executeCommand(String) is made, where Logic will executes the command.

  2. Upon a successful execution, a call to updateViewPanel() is made. In this method the ViewPanel then calls displayItems(ObservableList) again to rerender the items.

  3. displayItems will first have to clear all child Nodes that the ViewPanel contains before adding a new Collection of ItemCard.

  4. ViewPanelPlaceholder will then have to remove the ViewPanel child and add the new one to allow the changes to be reflected in the GUI.

You can refer to the activity diagram below for reference.

UpdateViewPanelActivityDiagram
If the execution by Logic is not successful, an error will be thrown and the ViewPanel will not be updated and refreshed.

Design Considerations

Aspect: How ViewPanel and AllItemsPanel updates
  • Alternative 1 (current choice): Updates taking in the lists as parameters.

    • Pros: Straightforward implementation that grantees correct result if the list is correct.

    • Cons: It breaks the "Model View Controller" structure because the UI is not listening to the ObservableList anymore. Whenever a command is executed, a function call has to be made to update the ViewPanel and the AllItemsPanel.

  • Alternative 2: Updates using event listeners

    • Pros: It follows the MVC structure where the panels listen to the ObservableList for changes.

    • Cons: As mentioned earlier, it is difficult to use event listeners on the SortedUniqueList because the listener will catch the sorting as modification to the items. In the future, alternative 2 can be considered with changes to how the listener and sorting works.

Aspect: Layout of ResultDisplay
  • Alternative 1 (current choice): Directly on top of the CommandBox with resizablility.

    • Pros: Long messages can be viewed and referred to when typing the next comment.

    • Cons: It takes up a fixed space on the GUI which could be used to display more items.

  • Alternative 2 (initial implementation): Use a pop up window to display the messages which disappears when any key is pressed and the user can continue.

    • Pros: It saves spaces on the GUI and success and error message can be dismissed so that user do not have to see it all the time.

    • Cons: User is not able to type while referring to the message.

Aspect: Layout of ItemCard

The original design does not fit the vertical list as seen below:

OriginalItemCard

The following changes have been made to the layout of the item card for a better view of the items.

  1. Display the number of days left before the item expires in an obvious manner for user to see.

  2. Move the position of the reminder and quantity to the left so that the right is not crowede.

  3. Dynamically Change the colour of the card depending on the status of the item. Red for expired, yellow for alerting, green for healthy.

  4. Expand the card on clicking and collapse it when not in focus to save space for more items to be displayed.