Overview
Coupon Stash is a desktop coupon manager that allows users to keep track of their coupons. The user interacts with it using a Command Line Interface (CLI) in the application, with an aesthetically pleasing GUI created with JavaFX. It is written in Java with about 15kLoC. This application caters to fast-typists as all of the commands and features can be executed using the CLI.
Summary of contributions
-
Major enhancements:
-
Added the ability to search for coupons by its expiry date/ month year (Pull requests #82 , #198 , #202)
-
What it does: Allows the user to view all his/ her coupons by the expiry date or the month.
-
Justification: This feature is essential for users to keep track of the expiry dates of coupons. The enhancement, with the calendar, will ensure that users know exactly when their coupons expire and will never forget to use them.
-
Highlights: This enhancement ties in closely with the calendar, which indicates if there is any coupon expiring on each date. It also ties in with other coupon fields to ensure the validity of a coupon (i.e. not expired), such as savings from the coupon. This feature is critical to the functioning of Coupon Stash as it directly affects the primary functions of Coupon Stash such as the automatic archiving of expired coupons and setting of a reminder 3 days before the expiry date.
-
-
Added Calendar Pane (Pull request #123)
-
What it does: allows user to have a bird eye’s view of the expiry dates of his/ her coupons on the calendar.
-
Justification: This feature is important for users to have a clearer view of the expiry dates of coupons with highlights on the calendar.
-
Highlights: This enhancement ties in closely with expiry date, as the calendar will highlight a date on the calendar if there is any coupon expiring on the specific date. The Calendar Pane changes with the observable list in the coupon list panel, which follows the Observer Design Pattern.
-
-
-
Minor enhancements:
-
Added start date field that allows coupons to have a starting date & to tie in with the expiry date (Pull requests #105 , #226)
-
Added the copy command that allows the user to copy the details of a coupon as an add command to the user’s clipboard (Pull requests #134 , #198 (Renamed from export to copy))
-
Added the goto command that allows the user to navigate the calendar using the CLI (Pull request #202)
-
-
Code contributed: Click on this RepoSense link to view the code that I have contributed to the project!
-
Other contributions:
-
Front-End Developer:
-
Project management:
-
Enhancements to existing features:
-
Expanded on the list command to list active, archived or active (i.e. not expired/ not archived) coupons (Pull request #198)
-
-
Documentation:
-
Tool:
-
Integrated a continuous integration workflow (Netlify) on GitHub into team repo
-
-
Contributions to the User Guide
Given below are sections I contributed to the User Guide. |
Listing all expiring coupons: expiring
Shows a list of all your coupons expiring on a date or during a month year.
This command will change the month year on display in the calendar to the month year of specified
expiry date or month year. For example, expiring e/30-9-2020 & expiring my/9-2020 both changes the month year on display in the
calendar to September 2020.
|
Format: expiring e/EXPIRY_DATE
or expiring my/MONTH_YEAR
Examples:
-
expiring e/30-9-2020
Shows you all the coupons that expire on 30 September 2020. -
expiring my/9-2020
Shows you all the coupons that expire during September 2020.
The expiring command will include archived
coupons in its results too. Coupons that are expiring in the archives are
displayed below the non-archived matches.
|
Listing coupons: list
Shows a list of coupons in the Coupon Stash.
There are 3 types of lists:
-
List of active coupons
-
List of archived coupons
-
List of used coupons
This command will change the month year on display in the calendar to the system’s date (usually today’s date). |
Format: list [PREFIX]
PREFIX can be left blank to list all active coupons (coupons that are not fully used/ not archived (except for
coupon(s) that are unarchived on purpose)).
|
Examples:
-
list
Shows a list of all active coupons in Coupon Stash. -
list a/
Shows a list of all archived coupons in Coupon Stash. -
list u/
Shows a list of all used coupons in Coupon Stash.
Copying a coupon: copy
Copies a coupon as an add
command to your
clipboard so that you can easily share it with your friends/family!
Format: copy INDEX
Below is a short demonstration of the copy
command:
copy
command operation.Examples:
Going to a month-year on the calendar: goto
Goes to the specified month and year on the calendar by changing the month year on display.
Format: goto my/MONTH_YEAR
Example:
-
goto my/12-2020
Goes to December 2020 on the calendar by changing the month year on display to December 2020.
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. |
Calendar
Current Implementation
The Calendar component provides a visual representation of the stored coupons that are expiring over a month. It is
facilitated by CalendarPane
, DateCell
, ObservableList<Coupon>
and ObservableMonthView
.
The CalendarPane
is the controller of the Calendar on display. Users can change the month on display to show the coupons
that expire during a specific month year by clicking on the arrows at the sides of the calendar’s title or
by using the goto
command.
Each DateCell
represents each date of the month that is currently on display. Each DateCell
uses the
ObservableList<Coupon>
to keep a list of the coupon(s) that expires on each date. A DateCell
with coupon(s) expiring
on the date are highlighted in red and a Datecell
that represents the system’s date
is highlighted blue.
The ObservableList<Coupon>
is the list of filtered coupons that are currently on display in the CouponListPanel
.
They are obtained by calling the Logic#getFilteredCouponList()
method. The list can be filtered to view all active,
archived or used coupons using the expiring
command .
The ObservableMonthView
is the current month & year on display in the Calendar Pane
. It is obtained by calling
the Logic#getMonthView()
method.
The class diagram below shows the interaction between classes that affects the Calendar:
The sequence diagrams below show how the Calendar works:
The two scenarios below are examples of how the Calendar mechanism behaves at each step of each scenario.
Updating the Calendar with an Updated List
The Calendar updates with the current ObservableList<Coupon>
with commands such as the add
, archive
, clear
,
delete
, edit
, expiring
, find
, list
, redo
, unarchive
, undo
and used
. The following steps describes how
this behavior is implemented.
Step 1. The user launches the application for the first time.
The Calendar displayed will render the saved coupon data, triggered by the initiation of the UiManager.
Step 2. The user executes a command that alters the ObservableList<Coupon>
(any command listed above).
When a command alters the observable coupon list, the listener of the observable list detects the change and the
Calendar will be updated accordingly to the list by calling the CalendarPane#fillUpCalendar()
method.
For example, the find
command alters the observable coupon list. It calls the FindCommand#execute(Model, String)
method, which calls the Model#updateFilteredCouponList(Predicate)
method. It then calls the
FilteredList<Coupon>#setPredicate(Predicate)
method that alters the observable coupon list.
If a command fails its execution, it will not call the FilteredList<Coupon>#setPredicate(Predicate) method. Hence, the
observable coupon list will not be altered and the calendar will not be altered.
|
The following sequence diagram shows how the Calendar updates with the observable coupon list:
Updating the Calendar with a Different Month View
The Calendar updates with the current ObservableMonthView
with commands such as goto
, expiring
and list
or by
clicking on the arrows at the sides of the calendar title. The following steps describes how this behavior is
implemented.
Step 1. The user launches the application for the first time.
The Calendar displayed will render the saved coupon data, triggered by the initiation of the UiManager. The default
calendar display will be set to the system’s month year
.
Step 2. The user executes a command that alters the ObservableMonthView
(any command listed above).
When a command alters the observable month view, the listener of the observable month view detects the change and the
month view display of the calendar will be updated according by calling the CalendarPane#updateCalendarWithYearMonth
method.
For example, the goto
command calls the GoToCommand#execute(Model, String)
method, which calls the
Model#updateMonthView(String)
method. It then calls the ObservableMonthView#setValue(String)
method that alters the
observable month view.
-
expiring
command-
For the
expiring
command, the Calendar will be updated accordingly to the month year of the specified date or month year with the command. -
For example, entering these
expiring
commandsexpiring my/9-2020
orexpiring e/11-9-2020
will change the month year on display to September 2020.
-
-
list
command-
For the
list
command, the Calendar will be updated to thesystem’s month year
.If a command fails its execution, it will not call the ObservableMonthView#setValue(String)
method. Hence, the observable month view will not be altered and the calendar will not be altered.
-
The following sequence diagram shows how the Calendar updates with the observable month view:
Or alternatively, instead of step 2,
Step 3. The user clicks on the arrows at the sides of the calendar title to change the month year displayed.
When a click alters the observable month view, the listener of the observable month view detects the change and the
month view display of the calendar will be updated according by calling the CalendarPane#updateCalendarWithYearMonth
method.
For example, clicking on the arrow on the right calls the CalendarPane#changeCalendarToNextMonth
method, which calls
CalendarPane#updateCalendarToNextMonth
. It then calls the ObservableMonthView#setValue
method that alters the
observable month view.
Design Considerations
Aspect: Information displayed on the Calendar
-
Alternative 1 (current choice): Show expiring coupons by highlighting the dates with expiring coupon(s)
-
Pros: Cleaner view of the Calendar with minimal information & may take up less space on the
Main Window
-
Cons: Lesser information provided with a glance
-
-
Alternative 2: Show a condensed version of the coupons' details within the cell of each date
-
Pros: More information provided with a glance
-
Cons: Messy to look at when there are multiple coupons expiring on a date & may take up more space on the
MainWindow
-
We decided on alternative 1, to show coupons expiring on specific dates with highlights. This is because a coupon contains
much information and the calendar may look cluttered and messy, which may be aesthetically unpleasant to the user.
Furthermore, the user can use the expiring
command to search for coupons expiring on a date or month year and have a
more detailed view of the coupons in the CouponListPanel
.
Aspect: Whether the Calendar should update with the list
-
Alternative 1 (current choice): Calendar updates with the filtered list
-
Pros: User can easily relate and reference to the coupons shown in the Calendar to the
CouponListPanel
-
Cons: May overlook some coupons if the list is filtered
-
-
Alternative 2: Calendar shows all the coupons in CouponStash
-
Pros: View of all coupons and will not overlook any coupons even when the coupon list is filtered
-
Cons: User may be confused if he/she sees a highlighted date on the Calendar when there is no coupon expiring on that date in the
CouponListPanel
-
We decided on alternative 1, for the calendar to update with the list in the CouponListPanel
. This is because this
follows the Observer Pattern Design Principle. Furthermore, this will not confuse the user when the user sees a
highlighted date on the Calendar when there is no coupon expiring on that date in the CouponListPanel
.
Coupon Reminder
To ensure users are aware of expiring coupons and maximise their saving, Coupon Stash reminds the user through a pop-up window, upon launching the application.
To achieve this feature, the following methods in the RemindDate
and
RemindWindow
classes are used.
-
RemindDate#isToday()
- Check if theRemindDate
is today. -
RemindWindow#filterRemindCoupons()
- Filters out allRemindDates
that are not today fromRemindWindow
. -
RemindWindow#constructRemindCoupons()
- Creates aString
of coupons that have theirRemindDates
today. ThisString
is used in the displayed reminder window. -
RemindWindow#showIfAny()
- Shows the reminder window if there are coupons to be reminded of today. If there are no coupons that have to be reminded today, no window will be shown.
To make sense of how coupon reminder functions, let’s dive into the specifics of RemindDate class, RemindCommand class and RemindWindow class.
Implementation of editing a coupon’s RemindDate
The following activity diagram depicts what happens when the user runs a
edit
command to edit a coupons’s RemindDate
.
remind date
of a coupon.Implementation of reminder pop up
After establishing the remind dates for all the coupons, the next step is ensure that there will be a reminder pop up (if necessary) upon opening the application.
The following steps describe how to reminder pop up works:
-
The user launches Coupon Stash. The
start
method inMainApp
class will kick start the program by setting up the stage, along with the saved data. -
This will trigger the
start
method inUiManager
, which leads to the creation of a newRemindWindow
instance, with aList
of all coupons currently stored passed in as a parameter. -
In the constructor of
RemindWindow
, coupons that do not have a remind date of today are filtered out. -
After filtering the coupons, if there are coupons to be reminded today, their information will be concatenated into a
String
that is displayed in the reminder window.
Design consideration
Aspect: How to keep track of coupon remind date
-
Alternative 1 (current choice): Coupon contains a
Remind
field.-
Pros: Code implementation is easier and this makes the remind date more visible to the user since it is a field.
-
Cons: Coupon display may get very cluttered with the addition of this extra field.
-
-
Alternative 2 : Store the remind dates of all coupons in a separate data file. Coupons can be stored in a hash table with their remind dates as keys.
-
Pros: No need to clutter coupon display with additional fields. Plus, it is efficient to list all coupons that have to be reminded for on a certain day as the coupons are stored in a hash table.
-
Cons: Hard to maintain two separate data files that have shared components (in this case coupons)
-
All in all, we chose alternative 1 as we feel that it is good for users to be able to view the remind date of a coupon in the coupon view. Additionally, all speed-ups and efficiency of storing the remind dates in a separate data file is nullified by the fact that we still need to loop through all coupons to display their remind dates on the calendar component. Thus, to make it easier to extend the program in the future, we decided against adding another data file which can make extension more complicated, and chose to work with alternative 1.