By: AY1920S1-CS2103-T16-1 Since: Oct 2019 Licence: MIT
- 1. Setting up
- 2. Design
- 3. Implementation
- 4. Documentation
- 5. Testing
- 6. Dev Ops
- Appendix A: Product Scope
- Appendix B: User Stories
- Appendix C: Use Cases
- Appendix D: Non Functional Requirements
- Appendix E: Glossary
- Appendix F: Instructions for Manual Testing
- F.1. Launch and Shutdown
- F.2. Saving Data
- F.3. Deleting a Record
- F.4. Average Command
- F.5. Achievement Commands
- F.6. Biography Commands
- F.7. Aesthetics Commands
- F.8. Motivational Quotes Feature
- F.9. Reminder and Event Command
- F.10. Reminder list side pane
- F.11. Calendar Command
- F.12. Food Recommendation Commands
- Appendix G: References
1. Setting up
Refer to the guide here.
2. Design
2.1. Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
The .puml files used to create diagrams in this document can be found in the diagrams folder.
Refer to the Using PlantUML guide to learn how to create and edit diagrams.
|
-
At app launch: Initializes the components in the correct sequence, and connects them up with each other.
-
At shut down: Shuts down the components and invokes cleanup method where necessary.
Commons represents a collection of classes used by multiple other components.
The following class plays an important role at the architecture level:
-
LogsCenter: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
Each of the four components
-
Defines its API in an
interfacewith the same name as the Component. -
Exposes its functionality using a
{Component Name}Managerclass.
For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.
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 delete 1.
delete 1 commandThe sections below give more details of each component.
2.2. UI component
API : Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, MainDisplayPane, MotivationQuotesLabel, ReminderListPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.
The UI component uses 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,
-
Executes user commands using the
Logiccomponent. -
Listens for changes to
Modeldata so that the UI can be updated with the modified data. (Not shown in class diagram)
2.3. Logic component
API :
Logic.java
-
Logicuses theSugarMummyParserclass to parse the user command. -
This results in a
Commandobject which is executed by theLogicManager. -
The command execution can affect the
Model(e.g. adding aRecord). -
The result of the command execution is encapsulated as a
CommandResultobject which is passed back to theUi. -
In addition, the
CommandResultobject can also instruct theUito perform certain actions, such as displaying help to the user.
Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.
delete 1 Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
2.4. Model component
UserSimilar structures can also be applied for Food, Record and Calendar.
API : Model.java
The Model
-
stores a
UserPrefobject that represents the user’s preferences. -
stores SugarMummy data.
-
exposes an unmodifiable
ObservableList(eg.ObservableList<Record>) 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. -
does not depend on any of the other three components.
2.5. Storage component
UserSimilar structures can also be applied for Food, Record and Calendar.
API : Storage.java
The Storage component,
-
can save
UserPrefobjects in json format and read it back. -
can save the SugarMummy data in json format and read it back.
2.6. Common classes
Classes used by multiple components are in the seedu.sugarmummy.commons package.
3. Implementation
This section describes some noteworthy details on how certain features are implemented.
3.1. Data Summary/Analysis feature
3.1.1. Average graph feature: Displays the average values of records in a line graph: average
The average graph shows how the average blood sugar level or BMI of users change over time. Daily, weekly, monthly average are supported.
Implementation
User input to get average graph is parsed by SugarMummyParser which creates a new AverageCommandParser.
AverageCommandParser then parses user input and creates a new AverageCommand. Next, AverageCommand
performs operations on AverageMap in Model with the help from RecordContainsRecordTypePredicate to
filter UniqueRecordList in Model. The result of the execution is returned to Ui as a
CommandResult object and is displayed to the user. In addition, Ui calls and displays average graph
related .fxml file to the user.
The average graph data points generation is implemented by AverageMap and the average values are stored
internally as internalMap. Additionally, it implements the following method:
-
AverageMap#calculateAverage()- calculates and stores the average values needed byAverageCommand. -
AverageMap#asUnmodifiableObservableMap()- returns a read only version ofinternalMap.
These operations are exposed in the Model interface as Model#calculateAverageMap() and
Model#getAverageMap() respectively.
Example Usage Scenario
Below is an example usage scenario and how average graph is created.
Step 1. User launches the application for the first time. The AverageMap will be
initialized and internalMap will be empty.
Step 2. User enters average a/daily rt/bloodsugar n/4 in SugarMummy to get daily average blood sugar.
Input is parsed and send to AverageCommand. AverageCommand then calls Model#updateFilteredRecordList()
to filter record list with RecordContainsRecordTypePredicate. This results in a list of
records containing only blood sugar records. Subsequently, AverageCommand calls
Model#calculateAverageMap() to update the internalMap to store 4 most recent daily average values based on the filtered
record list.
The following sequence diagram shows how the average operation works:
The lifeline for AverageCommand should end at the destroy marker (X) but due to a limitation of
PlantUML, the lifeline reaches the end of diagram.
|
Step 2a. If the user enters average a/daily rt/bloodsugar n/4 and there is no data available,
then the command will fail to execute and throw a CommandException. Alternatively, if user enters
an invalid command, a ParseException will be thrown.
This is illustrated in the activity diagram below.
Step 3. Ui receives average CommandResult from LogicManager and creates a new AverageGraphPane
as well as all other necessary components (see below). Ui then displays the AverageGraphPane to
user.
Average graph Ui consists of several parts:
-
AverageGraphPane: Placeholder forAverageGraphandLegendPane. -
AverageGraph: Contains the average graph. Data points are generated byinternalMap. -
CustomLineChart: The implementation for average graph which extends and override JavaFxLineChart. -
LegendPane: Placeholder forLegendRow. This is the legend box for average graph. -
LegendRow: Consists of a colored legend symbol and its description.
Aspect: How to display average graph to user.
The dilemma arises because users, especially recently diagnosed type 2 diabetics, do not know the normal range of BMI and blood sugar level. An intuitive and aesthetically pleasing method is needed to convey this information to user.
-
Alternative 1: Use JavaFx
LineChartto display the average graph and display the ranges below the graph using JavaFxLabel.-
Pros: Do not need to implement anything.
-
Cons: User need to trace data points to the y axis to find it’s value and compare it with the ranges given below the graph. This can be annoying and tedious for the user.
-
-
Alternative 2 (current choice): Override JavaFx
LineChartby adding horizontal range markers to the graph and color the area between the markers.-
Pros: User is able to tell which range a particular data point falls in immediately.
-
Cons: Need to implement horizontal range markers and lay it out on the graph. In addition, a custom legend box is needed to label the horizontal range markers.
-
3.1.2. Data Summary/Analysis Feature coming in v2.0
[Proposed] Summary statistics of a particular record type [coming in v2.0]
The implementation will be similar to average graph feature. The UniqueRecordList can be filtered
the same way as average graph feature to get a list containing only the specified record type.
If only records from a certain time period is needed, a new date predicate class needs to be created
to further filter the UniqueRecordList by starting and ending date. Using the filtered record list,
count the number of low, normal and high values based on some threshold set by the developer. These
counts will then be displayed using JavaFX PieChart. Also calculate the minimum, maximum and average of the
filtered record list. These 3 statistics will be displayed right under the pie chart as plain text.
[Proposed] Shows relationship between record types: [coming in v2.0]
The implementation will be similar to average graph feature. But now, UniqueRecordList needs to
be filtered so that it only contains the two record types needed. To do this, future developer
need to tweak the current RecordContainsRecordTypePredicate to be able to filter two different record types.
Since SugarMummy only supports two record types now, filtering UniqueRecordList is
redundant. However, this implementation consider the situation that more record types may be added
in the future.
|
Using the filtered record list, pair two different record types from the same day together and this pair
represents a data point. Discard records that cannot be paired. Once the pairing process finishes,
display the points in JavaFX ScatterChart.
[Proposed] Exports summary of all medical records into pdf [coming in v2.0]
This feature can be implemented using PDFBOX libraries or any other existing libraries.
3.2. Data log feature
3.2.1. Implementation
The multi-record data logging mechanism is facilitated by a new Record package containing BloodSugar and Bmi classes that extend an abstract Record class. Add, list and delete command classes and parsers are modified to accommodate multiple record types. Multi-record data is stored internally as a recordList where members are Records.
It modifies the following operations:
-
SugarMummy#add()— Adds a record to the record list. -
SugarMummy#delete()— Deletes a record from the record list. -
SugarMummy#list()— Retrieves all records in record list.
These operations are exposed in the Model interface as Model#addRecord(), Model#deleteRecord()
and Model#getUniqueRecordListObject() respectively.
The internal data structure contains an ObservableList<Record> that the UI can observe to display the record list.
Below is an example usage scenario of how the data log feature behaves at each step.
Step 1. The user launches the application for the first time.
If /data/recordList.json is not found, it will be produced from SampleRecordDataUtil#getSampleRecords().
If /data/recordList.json is found, the recordList will be loaded from there using UniqueRecordList#setRecord()
and checked for inconsistencies e.g. missing fields, invalid fields.
If inconsistencies are detected, an Exception is thrown and existing recordList.json is erased.
Step 2. The user lists all records.
A new RecordListPanel is created and populates each ListViewCell with BloodSugarRecordCard and BmiRecordCard.
ObservableList<Record> is used to populate the ListViewCell.
Step 3. The user executes add rt/BMI h/1 w/1 dt/2019-09-09 12:12 command.
The add command parameters are parsed for validity and uniqueness.
This job is delegated to the following classes:
SugarMummyParser,AddCommandParser and ParserUtil.
This is illustrated in SequenceDiagram below.
After parsing is completed, either a complete `BloodSugar or Bmi Object is returned otherwise a ParseException will be thrown.
The Record is checked against the model for uniqueness.
If it is unique, it is added to the Model via Model#addRecord() (illustrated by the red portion of the sequence diagram below)
The above activity diagram illustrates step 3.
The above sequence diagram provides a in-depth look at how parsing is delegated to various classes within the blue Logic component. The calls to the red model component illustrates Step 3 adding records to the model. The final call to the yellow storage component illustrates step 5.
Step 4. The user decides to delete a record.
The delete command is parsed for validity by SugarMummyParser, DeleteCommandParser and ParserUtil.
ParseUtil checks whether the index is a positive number, otherwise a ParseException will be thrown.
DeleteCommand checks whether the positive index points to a valid record.
DeleteCommand will call Model#deleteRecord() to remove the record from the list.
Step 5. After add or delete commands have been executed in LogicManager, the Model’s recordList is written to recordList.json using Storage#saveRecordList().
3.2.3. Aspect: Commands and parsers implementation
-
Alternative 1 (current choice): Parse for new record type X within existing add, list, delete commands and their parsers
-
Pros: Easy to implement as long as record type X inherits from Record. AddCommand, ListCommand and DeleteCommand classes remain very similar to their original implementations.
-
Cons: Harder to debug when parsing fails because XCommandParser classes are responsible for checking for presence of multiple fields of multiple record types.
-
-
Alternative 2: Create separate AddX, ListX, DeleteX, AddXParser, ListXParser, DeleteXParser for each new record type X introduced
-
Pros: Each parser is responsible for parsing only record type X’s fields. This narrows down the scope of debugging should parsing fail.
-
Cons: Accommodating a new record type involves creating at least 6 additional classes just for operations on data classes. Data classes required to represent the data include: Bmi class with Height and Weight class.
-
3.2.4. Aspect: Data Structure for managing multiple record types
-
Alternative 1 (current choice): Use a single list to store multiple record types.
-
Pros: Easy to understand and implement.
-
Cons: Must conduct type checks when retrieving from list. When a new record type is added, all type checks in different places must be updated.
-
-
Alternative 2: Use separate lists to store different record types.
-
Pros: Do not need to perform type checks when retrieving from list.
-
Cons: Listing all records together becomes difficult, must build a new list from all separate lists. Each class must reference a different kind of list.
-
3.3. Calendar feature
3.3.1. Implementation
Overview
The calendar feature is mainly supported by Calendar along with a Scheduler. Calendar stores internally a calendarEntries list, a pastReminders list and a Scheduler.
It also handles checking for duplicate and overlapping calendar entries.
Calendar entries consists of Reminder`s and `Event`s. `calendarEntries list is an unique list for all calendar entries added
by the user. Aside from it, pastReminders list is dynamically determined by time. The Scheduler, which utilizes java ScheduledExecutorService is responsible for adding reminders at specific time to the
pastReminders list and all reminders in this list is shown to the user. The real-time reminder works parallel with all other features in this app. Also Scheduler keeps track of the current date and the starting
time of running the app.
Calendar implements the following operations:
-
Calendar#addCalendarEntry— Adds a new calendar entry to the calendar. -
Calendar#addPastReminder— Adds a reminder to the past reminders list. -
Calendar#getCalendarEntryList— Gets a list of calendar entries. -
Calendar#getPastReminderList— Gets a list of past reminders. -
Calendar#schedule— Schedules a series of upcoming reminders.
These operations are exposed in the Model interface as Model#addCalendarEntry(), Model#addPastReminder(),
Model#getFilteredCalendarEntryList(), Model#getPastReminderList() and Model#schedule() respectively.
Reminder and Event class
Basically, both Reminder and Event which extend from the abstract class CalendarEntry consist of a Description and a DateTime field.
For Reminder, the DateTime field represents the time of the reminder and the date from which the reminder starts.
It has a field of Repetition, which is an enum class representing Daily, Weekly or Once repetition type of the reminder.
For Event, it has another optional DateTime field and an optional Reminder field. The compulsory DateTime field is the starting date time while the optional one is the ending date time. The Reminder
is for an auto reminder created by the app if the user requires in the command.
See the class diagram below for calendar related classes.

EventCommand and ReminderCommand class
To add events or reminders, the calendar system implemented EventCommand and ReminderCommand. Before adding an event, the calendar system will check whether any duplicate event exists and any events overlap
with the new event by comparing the DateTime attributes.
The execution of the ReminderCommand involves checking whether any duplicate reminder exists also. Due to probable recurrence of reminders, it also
checks if any reminder can fully cover the new reminder by comparing DateTime and Repetition. In this case, the new reminder will not be added. Besides, if the new reminder can cover other reminders, new reminder
will replace them. For those overlap but cannot be resolved, the system will not add the new reminder either.
Scheduler class
To show reminders at certain time, the Scheduler utilizes java ScheduledExecutorService to schedule a future task with a delay. It creates two inner classes implementing the Runnable interface for tasks. The ReminderAdder
class represents a task of adding a reminder to the past reminder list. Initializer class represents a task of initializing the scheduler at the beginning of a day.
The following activity diagram shows how scheduler works when it is called to schedule tasks:

-
Range of tasks scheduled
-
To calculate the accurate delay time for each reminder, the scheduler keeps track of starting time for all the scheduled tasks and the delay is the time duration between this starting time and the reminder time. Apart from the starting time, there is a deadline for the scheduler which limits the time range for scheduled reminder tasks. So the scheduler only schedules tasks for reminders between the starting time and the deadline. In addition, before scheduling tasks, all reminders with the same time are grouped together by using a
TreeMapto map from each time to a list of reminders so they can be added to the past reminder list together. -
After the app is launched, the
Scheduleris called to initialize tasks. The starting time is set to be the starting date time and the deadline is set to be 23:59 on the same day. Thus only reminders on the current date is scheduled. During the app running,Schedulercan be called to reschedule tasks because of adding new reminders or removing reminders. This will adjust the starting time for scheduling to the current time while the deadline remains the same. Due to the limited number of threads and unknown number of upcoming reminders, the scheduler will cancel all the tasks that have not been executed and then schedule upcoming reminders that fall between the new starting time and the deadline. Each time any reminder being added or removed, the scheduler is triggered to reschedule tasks.
-
-
How to move on to next day
Besides scheduling tasks of adding reminders, the scheduler always schedules a task withInitializerclass for initializing right after the current deadline, so that it can transfer smoothly to the next day if the app is open overnight. This initializer will set the deadline to be end of the next day, update date and schedule tasks.
The following activity diagram shows an example of how event command and scheduler work together:
Example usage scenario
Given below is an example usage scenario and how the calendar behaves at each step.
Step 1. The user launches the application for the first time on Dec 14 2019 09:00(local time). The Calendar will be initialized with the initial calendar state, which includes an empty calendar
entry list and an empty past reminder list.
Step 2. The user executes reminder d/insulin injection dt/2019-12-14 17:30 r/daily command to add a new reminder of 'insulin inject' at 17:30 every day. The reminder command calls Model#addCalendarEntry(),
causing the modified state of the calendar after the reminder command executes to be saved in the calendarEntries list. Subsequently, it calls Model#schedule() which forces the scheduler to update the upcoming
reminders.
Step 3. The user executes event d/meeting dt/2019-12-14 14:30 tp/00:30 command to add an new event with an auto reminder scheduled 30 minutes
before the event. It calls Model#addCalendarEntry(), causing a new event as well as a new reminder saved in the calendarEntries list. Subsequently, it calls Model#schedule() which forces the scheduler to
update the upcoming reminders.
If an event or reminder command fails its execution, it will not call Model#addCalendarEntry(), so the calendar state will not be saved into the calendarEntryList.
|
Step 4. At 14:00, a scheduled task is executed to call Calendar#addPastReminder() and it adds the dinner event reminder to the pastReminders list.
Step 5. At 17:30, a scheduled task is executed to call Calendar#addPastReminder() and it adds the dinner event reminder to the pastReminders list.
The following sequence diagram shows how a single reminder command works:
CalendarCommand class
CalendarCommand is implemented for showing calendar entries and monthly calendar. It consists of a YearMonth, an optional YearMonthDay, isShowingWeek
and isShowingRaw fields. The result of executing a CalendarCommand is a subclass CalendarCommandResult extending from CommandResult, which will be considered
differently in the MainWindow. MainWindow will create a pane depending on the attributes of CalendarCommandResult.
3.3.2. Design Considerations
Aspect: How scheduler updates upcoming reminders
-
Alternative 1 (current choice): Cancels all scheduled reminders and reschedule according to the updated reminder entries.
-
Pros: Easy to implement.
-
Cons: May have to do duplicate work of scheduling. May have performance issues in terms of time.
-
-
Alternative 2: Updates scheduled reminders according to the newly added reminder.
-
Pros: Will has less repeated work.
-
Cons: More work to do on deciding which tasks to cancel.
-
Aspect: Period of updating scheduler.
-
Alternative 1 (current choice): Updates scheduler at 23:59(local time) every day.
-
Pros: Good consistency.
-
Cons: May have a large number of scheduled tasks which will not be executed before the application is closed.
-
-
Alternative 2: Updates scheduler every hour.
-
Pros: More flexible scheduling without concerning date and less scheduled tasks.
-
Cons: May cause overhead due to frequently updating.
-
Aspect: Resolution of overlapping reminders
-
Alternative 1 (current choice): Force to replace subset reminders with new superset reminders which fully cover existing reminders.
-
Pros: Avoid duplicate reminders added which the user may not be aware of.
-
Cons: May remove some reminders that the user was not intent to do.
-
-
Alternative 2: Asks for user’s permission before proceeding.
-
Pros: Can avoid unintentionally reminders deleting.
-
Cons: May cause some duplicate reminders.
-
3.4. Personalised User Experience Feature
To personalise the diabetic user’s the experience in using the SugarMummy app, several sub-features are used, including:
-
Addition, editing and clearing of the user’s biography
-
Customisation of font and
backgroundcolour, with the ability to set asbackgroundimage forbackgroundas well. -
Display of motivational quotes for the user (initialisation phase; in progress)
-
Achievementsto be shown to the user upon achieving a milestone.
3.4.1. Overview
-
The
Userclass is used to represent a diabetic user. A diabetic user is composed of theName,ProfileDesc,DisplayPicPath,Nric,Gender,Phone,MedicalCondition,Address,GoalandOtherBioInfoclasses. -
A
Useris currently defined to be able to have more than onePhone,MedicalConditionandGoal. As such, these classes inherit theListableFieldInterface. -
The structure of a
Userand its interactions are shown as follows:
-
A
UserimplementsListableFieldby storing them in a javaList. -
A
Userthat is created is added to aUserList. Although not more than oneUsercan be added in current versions so as to enhance personalisation for the, future developers may decide to repurpose the app to allow more users, and their corresponding biographies represented by thebiofields, to theUserList. -
Other personalisation features such as
fontcolour,backgroundandachievementsare currently represented by independent classesColour,BackgroundandAchievementrespectively on their own, representing the model as their name describes. -
The
Colourfeature allows for either enumeration of colour names or hexadecimal colour codes to be used to set colour.Backgroundis associated toColouras an argument forBackgroundcould simply be a colour. It depends on the static method isValid`Colour`(String test) method to determine if it’s argument is aColour -
The
AddBioParserandEditBioParseris currently used to parse command arguments given by the user and allows adding of specific biography fields, whereas theFontColourandBackgroundparsers are used to parse arguments for other personalisation features for font colours andbackgroundrespectively. -
The
Uifor personalisation is separated into distinct parts.User’s biography information and achievements page are components on their own in theUi’sMainDisplayPane– switched when required, whereasbackgroundandfontcolourdo not have a designatedUiwindow, but instead changes the attributes for the entire application by modifying the CSS file used itself. -
All command words in this program, not restricted to this feature alone, are not case sensitive and implemented under
SugarMummyParser.
3.4.2. Implementation
Biography
The biography feature is supported by the addbio, editbio and clrbio commands.
Each command adheres to the main
flow of information used by this application. In other words, when a command is received, the command is first parsed
by SugarMummyParser, and to individual parsers where required, before return a Command object. The Command object
is then executed by LogicManager, during which it updates ModelManager, and after which Storage is updated, before feedback from
the CommandResult returned by the Command object is shown to the user back at the Ui.
-
The following are possible scenarios for each of the following types of command words.
-
Scenario 1: User keys in
addbio n/test minimal p/91234567 e/81234567 /test medical condition -
Scenario 2: User keys in
editbio p/2/91234567 -
Scenario 3: User keys in
bio -
Scenario 4: User keys in
clrbio
-
-
In all scenarios,
SugarMummyParserresponds to the command word via a series of switch cases. As mentioned above,addbioandeditbioreturnsAddBioCommandParserandEditBioCommandParserrespectively. -
A key difference between the parsers for
addbioandeditbiois that the former requiresName,ContactNumber,EmergencyContact, andMedicalConditionto be compulsory whereaseditbiorequires at least one argument denoting theUser’s biography field to be changed. Furthermore,EditBioCommandParserdetermines whether or not subarguments for fields ofListableFieldtype contain the formatINDEX/, denoting the particular number in the list to be changed. -
CommandParserthen returns anAddBioCommandobject that stores theUserto be created.EditBioCommandParseron the other hand creates anEditBioCommandobject that stores anEditedUserDescriptioncontaining information on which fields are edited to be edited.-
A
ListofHashMapsthat maps indices toListableFieldis used inEditedUserDescriptionto denote changes to be made within eachListableField. When executed byLogicafterwards, theAddBioCommandcreates theUserto be stored in theModelManagerwhereas theEditBioCommandcreates a newUserbased on information inEditedUserDescription. AUserListis used in theModelManagerto storeUserinstances. -
At any point of time when a user attempts to access biography information,
LogicManageraccesses theUserListfromModelManagerto display information. In order to be able to display the same information upon startup,LogicManagersaves thisUserListto the storage after execution of each command.
-
-
For the
bioandclrbiocommands, the implementations are relatively more straightforward.-
A
BioCommandreturned bySugarMummyParsersimply overrides thegetDisplayPaneType()of theCommandobject (that eachCommandobject contains) so that back atUi,Uiknows to display theBioPaneof theUiin theMainDisplayPanepart of the window. -
This is also done for all other biography-related commands so after each biography-related command, the
BioPaneis displayed. ADisplayPaneis stored in the form of an enumeration as the type of display would be predefined to all it’s accessors. TheClearBioCommandclass simply clears theUserListstored in theModelManagerupon execution.
-
-
In the cases of
bioandclrbiocommands,SugarMummyParserrequires non-null arguments just as it does for other single-word commands such asexit. -
Each
Commandreturns aCommandResultto logic containing feedback to be displayed to the user. Any exception that is thrown to the user is caught back atUiUi. Feedback is displayed to the user using theResultsDisplayPane. The display of user biography is implemented using JavaFXTableView. If theDisplayPicPathof aUseris unchanged, theUidoes not reload the image, so as to optimise performance of the program. If an entire pane is left unchanged, the pane is not reloaded, even upon execution of commands that are used to display the pane, unless explicitly indicated in thegetNewPaneIsToBeCreated()method of the.Command. Caching is implemented using aHashMapthat mapsDisplayPaneenumerations to the correspondingUiPartrepresenting the respective pane. -
An illustration of how the information flows for the
editbiocommand is shown as follows:
-
The rest of the biography commands follow a similar logic, with key differences in the parser and command steps as described above. Validation within parsers are done via the
ParserUtilclass.
Aesthetics
The aesthetics aspects of the application help to support the feature of personalised user experience and are
implemented using the command words fontcolour and bg respectively.
-
Possible valid usages are as follows:
-
Scenario 1: User keys in
fontcolour -
Scenario 2: User keys in
fontcolour white -
Scenario 3: User keys in
fontcolour #FFFF00 -
Scenario 4: User keys in
bg -
Scenario 5: User keys in
bg #000000 -
Scenario 6: User keys in
bg blue -
Scenario 7: User keys in
bg /Users/John/displayPicture.jpg s/cover -
Scenario 8: User keys in
bg r/no-repeat
-
-
As mentioned above,
ColourandBackgroundare independent classes, andColourmakes use of enumerations of colour names and hexadecimal colour codes to determine validity of the colours. -
Upon receival of the command
fontcolour, iffontcolourhas no arguments (checked byFontColourParser), a newFontColourCommandwith no arguments is returned, and upon execution return aCommandResultthat shows the existingfontcolourused via access ofModelManager(logic is similar to the ones for biography)-
Otherwise if arguments are received, validity of the arguments is checked against, and if the colour is a valid
Colour, it is set inModelManagerand saved to Storage.FontColourCommandoverrides thegetDisplayPane()to return theDisplayPane.COLOURenumeration. i.e. theMainDisplayPaneis unchanged inUi, and only font colours change.
-
-
Backgroundon the other hand, checks for additional possible arguments. First of all, as observed in Scenarios 6 and 7, an argument could either represent aColouror a path leading to an image to be used to set the background picture (this is similar to theDisplayPicPathofbiofield). Thus,BackgroundParserfirst determines if the argument received is aColour. If so it returns aBackgroundCommandstoring aBackgroundthat has abackgroundColourattribute. Otherwise, it checks, viaParserUtil, whether or not the argument before valid prefixes (preamble) is a valid file path. If so, aBackgroundthat has abackgroundPicPathattribute is used to create theBackgroundCommand.-
Otherwise a
ParseExceptionis returned. Possible arguments that abgcommand can have include the size and repeat feature, corresponding to CSSbackgroundattributes. -
In current versions of the program, the program allows for fixed constants of this features to be used, that are stored in
BackgroundImageArgsclass and used by theBackgroundmodel for validation. -
BackgroundCommandoverrides thegetDisplayPane()method to returnDisplayPane.BACKGROUNDenumeration. i.e. theMainDisplayPaneis unchanged inUi, and only thebackgroundchanges. -
Similar to font colour, the command word on its own simply displays to the user current
backgroundsettings. -
An illustration of the logic for handling a
bgcommand is shown as follows:
-
-
The
ImageAnalyserclass used to determine a background image’s dominant colour is inspired, collectively, by Zaz Gmy’s code example and user mhshams's code snippet.-
For both
fontcolourandbgcommands, the StyleManager class ofUiis used to set the user’s intention offontcolourandbackground(if parsing is successful). The way StyleManager sets thebackgroundis by making a copy of the existing StyleSheet used, modifying the required fields and setting it to the StyleSheets of the scene, internally. -
Perhaps an interesting area of the
ColourandBackgroundcommands in more recent updates would include implementation using command composition. The driving factor that fueled this is the need to ensure theFontcolourandBackgrounddo not have colours that are too similar (or otherwise the text could get difficult or impossible to see). This above-mentioned checking was implemented by summing the square of the differences in red, green and blue channels' values between theColourof theFontcolourandBackground. -
The
Colourfor aBackgroundwith an image instead of a solidColouris determined by extracting theColourthat appears the most often using theImageTesterclass. -
An major issue with checking for colour differences would be the situation when the user intends to make changes to a
Fontcolourthat clashes with theBackgroundif changed. Take for example a change infontcolourintended to be changed from white to black, with a background that is curently already black. The system would not have allowed changes of the text from white to black because of the background’s black colour and would have suggested to change the background first. The background is required to be changed to something much lighter so that the background can be set to black. However, if the background cannot be changed to something that is lighter than it’s current colour but yet dark enough not to clash with the current background colour, then the user could find it hard to switch to the new colours without going through a series of specific steps that would not cause colour clash. -
Command composition allows the
bgandfontcolourcommands to be combined such that the user is able to set both thebackgroundandfontcoloursimultaneously, and as such colour comparison is made solely between the new colours entered rather than any of the current colours. -
BackgroundParserparses forfontcolour/and its arguments whileFontColourParserparses forbg/and its arguments. Any of these prefixes observed results in the Parser generating aFontColourCommandandBackgroundColourCommandrespectively.BackgroundParserthen returns aBackgroundColourCommandthat has aFontColourCommandstored in it and vice versa. WhenLogicManagerexecutesBackgroundCommand, for instance,BackgroundCommandexecutes theFontColourCommandstored in it as well. The necessary adjustments are made to model accordingly and the feedback to users from both commands will be returned to the user. -
The idea of a command running another command allows commands such as
bg black fontcolour/redto be entered by the user. Modified methods in theArgumentMultimapclass of thelogicpackage also allows the program to ensure that the user does not enter multiple arguments of the same type at once eg. disallowingbg black fontcolour/red fontcolor/yellow.
-
Achievements
-
A diabetic user’s
Achievementsis supported by theachvmcommand, that displays the list of user’s achievements. Similar to howbiois implemented,SugarMummyParserreturns anAchievementsCommandthat overrides thegetDisplayPane()method to returnDisplayPane.ACHVM– such thatUiofUisets the children of theMainDisplayPanenode to be theAchievementsPane. EachAchievementis represented using anImageViewin JavaFXTilePaneso that all images are of the same size. -
An
Achievementis implemented as an abstract class in themodelpackage. Each achievement contains attributes that define theAchievementsuch as itstitleanddescriptionwhich specifies the requirements needed to attain it. A significant attribute of theAchievementclass is it’s three states -Achieved,Yet to AchieveandPreviously Achieved. Another would be thelevelof the achievement (eg.Bronze,Silver,Goldetc.) -
Current
Achievementobjects haverecordTypeBmiandBloodSugar, with corresponding interfaces that represent theAchievementfor itsRecordType. Specific classes inherit theBmiandBloodSugarinterfaces while extending theAchievementabstract class to specify defining attributes and methods. -
When the program starts, an
AchievementsMapcontaining aMapofRecordTypetoListof allAchievementobjects that the program has is created inModelManager. AllAchievementobjects are initially all at the state ofYet to Achieve. -
The
AchievementStateProcessorclass is then called, which iterates through the list of allRecordelements stored inModelManagerand updates theStateof eachAchievementif necessary. -
For each
RecordTypeandLevelofAchievement, theAchievementStateProcessorclass checks whether the records fulfils the requirements for a predefined number of consecutive days. Requirements are in turn determined by theMAXIMUMandMINIMUMvalues stored in the interfaces of theAchievementclass. State changes are made to theAchievementclass if requirements are fulfilled (eg. if the number of requirements of aRecordTypeforGoldare met, then theAchievementoflevelGoldand of that particularRecordTypewould have it’s state updated to reflect that change. This is accomplished using methods such as thepromoteanddemotein theAchievementStateProcessor). -
In order to determine whether requirements are fulfilled, interaction with not only the
RecordTypeis implemented, but also the methods of theAveragefeature (to obtain daily averages of record types before comparing them). -
A notable aspect of the implementation is the reversal of
levelfrom high to low level. This is such that if a higher-levelAchievementhas been achieved, lower levels of achievement would also have been attained. In such cases, the program automatically sets lower levels ofAchievementto be achieved without having to iterate through the rest of theRecordelements in theRecordList. -
Thereafter, for each addition and removal of
Recordelements, the same process described above is used to update theAchievementsMap, that mapsRecordTypeto anAchievementsListofAchievementelements with updatedStateattributes. -
When the
achvmcommand is received by the program, thisAchievementsMapis simply retrieved fromModelManagertoLogicManagerand the corresponding images representing theAchievementobjects in the list, with theirStatevalues, and attributes are presented to the user via theMainDisplayPaneof theMainWindow. -
If the
AchievementsListhappens to be unchanged since the last time the pane is loaded in the same session, the pane is not reload so as to optimise performance of the program and minimise unnecessary access and loading of images.
-
The full list of
Achievementitems, as well as correspondingStateandLevelpossible to attain for eachRecordTypein the current version of the program are shown as follows:
-
Each
AchievementStateis represented by hand-drawn images, which were coloured digitally using Adobe Photoshop. If a developer intends to modify or extend the current list ofAchievementitems, he or she may also modify or add on to these images that are currently located in/view/images/achievements/of the project directory.
Motivation
-
Motivational aspects of the application are supported using motivational quotes.
-
Each motivational quote exists as a
Stringin an unmodifiableListof the classMotivationalQuotes. -
The
Listof quotes (collated from different sources but modified to have the same formats) are initialised to be part ofModelManagerwhen the program first starts up. -
Upon initialisation of the program, the
MotivationalQuotesLabel.fxmlfile is referenced via its corresponding class. -
Retrieval of the
Listof motivational quotes is done viaLogicManagerwhich accesses theListof motivational quotes inModelManager. -
A quote is randomly selected and then displayed to the user via the program’s user interface.
3.4.3. Design Considerations
Number of Users
-
It could be argued that multiple user support is not required and thus a
UserListshould not be used to store data. However, the intention is to leave it open to future developers to decide on whether to include multiple user support for the application, as the choice of a fully personalised experience for diabetic patients versus functionality for multiple users (having diabetes and using the same app), as well as the possibilities of such scenarios are debatable. Furthermore, our user stories appear to suggest the desire for a more personalised application. -
In the strict case of single-user support that leaves the app less open to such modification, the alternative would be to simply implement and store the
UserinModelManager, rather than theUserList.
Background Sub-Argument Values
-
The use of
enumis a possibility to implementstatic final backgroundsub-argument values (eg,autoof attributebackgroundsize). However considerations that eventually led against this idea included the possibility of values that are not in properStringformat that may not be able to be directly enumerated (leading to the required use of additional lengthyswitchcases). Additionally otherbackgroundfields may be added by future developers and it could be more concise to have them all in a single class rather than as separate enumerations.
Command Classification
-
It is possible to separate the commands for
fontcolourandbackgroundinto different commands (eg.addfontcolour,editfontcolour,showfontcolour,clrfontcolour). However, this is likely unnecessary as this will not only require the end user to type more words, but also introduce redundancy (eg.clrfontcolourcould simply befontcolour blackand still achieve the same effects asclrfontcolour).
Modification of Application Style Dynamically
-
An alternative idea to achieving
fontcolourandbackgroundthroughout the entire app was to visit eachJavaFXchildNoderecursively and set the colours and backgrounds if the nodes are of specific instances with these attributes (eg.Labelwhich hastextfillattribute). However, this idea was quickly aborted as theTableViewimplemented only renders headers after the scene has been set and to include such a case in the recursive solution adds significant complexity to the program on top of the possibility of severely breaking abstraction.
Restricting User Modification of Motivational Quotes
-
The user is specifically designed to have no access in modifying the list as that would not only have taken away the element of surprise but defeat the purpose of motivating the user one step at a time.
-
Additionally, no additional commands for switching quotes are implemented as the user may simply restart the application to generate a new
MotivationalQuoteout of the 600+ that are currently available. -
Future developers may decide to add more quotes, or implement the capability for users to add or modify them, but at the moment we believe modification would be unnecessary as user-defined fields may also be achieved via other existing features such as those in the biography. A user may furthermore add to quotes that may turn out to be discouraging without knowing it, or accidentally delete quotes from the list unintentionally, making the user experience of the feature much less deterministic.
-
Daily motivational quotes were replaced with motivational quotes that change every time the application is restarted as not only does it increase ease of testability, but also allows the user to encounter something different each time the application is opened. Given the minimal ability intended for the user to modify the quotes, it is perhaps important that a user who may not like what he is seeing on screen, or simply wishes to see something different. does not have to wait till the end of the day in order for a change in quote to be observed.
3.4.4. Achievement Measures and Criteria
-
It was difficult to define what a user needs to 'achieve' before he or she gets an achievement.
-
The basic idea was to allow for different achievement levels which was eventually implemented. However, marking of the boundaries of when a user attains an
Achievementwas debatable and could still be amongst developers. -
An initial consideration was to award users achievements based on the average of the data in their health records. In other words, take the average of all data within a specific time period and award the achievement if the data within that time period matches the requirement. However a major flaw with this idea was how users would eventually be able to 'cheat' - by minimising the number of days during which records are entered, and only recording data when results are desirable. The other issue was the duration during which the average was determined. Suppose an achievement may be attained by the user upon meeting requirements based on data over a year on average. This means that a user could enter a record that meets the requirements in year 1, and then one year later enter another record that meets the requirements. By this definition of achievements, the user could have received the achievement even though the records may not have met requirements for the majority of year (especially for records that were not keyed in).
-
Thus, user’s achievements were defined by the actual duration during which they met requirements, and furthermore for consecutive number of days. i.e. streak
-
This ensures that the user is incentivised not only to achieve good records (and in the process improve his or her health), but also acquire a good habit of keying in and storing records.
3.4.5. Future Developments
Saving of user’s preferred themes: [coming in v2.0]
This feature has not currently been implemented, but could possibly be implemented using the existing
StyleManager class, which processes users' background and fontColour. A List could be used to save an
archive of users' preferred themes during that session.
Adding, editing and deletion could be accomplished using List
methods. A HashMap could also be used such that the user can self-define names for each of the themes.
A variable would serve as a current pointer to determine the current theme the user is using. A change in theme could
be achieved by updating the pointer and / or the HashMap, if any is implemented.
If the user does not have any themes, then default aesthetics would be loaded, or if there is at least one set of saved
settings (as there is in this current version of the application), the users' preferences' in those settings would be
loaded.
Upon termination of the program, the contents of the HashMap could be saved to a JsonStorage file.
Displaying of cartoon avatar that represents the user: [coming in v2.0]
This feature has yet to be implemented but could possibly be implemented using a class / method that interacts with the
user’s RecordList. A higher-value BMI of the user could be represented by a figure with a wider profile while a lower-value BMI
could lead to the avatar being represented otherwise. Users could also have the option to enable and disable this feature.
This dynamically changing avatar could be achieved by combining shapes that change according to the values in RecordList,
or by using an existing library that allows for this.
Follow up on user’s goals: [coming in v2.0]
This feature has yet to be implemented but could possibly be implemented by first parsing inputs that the user has
entered for the Goal fields. If in a format that is recognised, the program would store the recognised
parsed Goal and corresponding LocalDate in an ArrayList and JsonStorage file. The program would then check
the user’s progress over time by analysing data in the user’s RecordList, and provide timely feedback by
comparing the current date and date by which to reach the Goal targets set.
For instance, the program may display a new alert-box like window via the UI indicating to user 'good job' for perhaps
being 'halfway there' in attaining set goals.
This feature may also implement some methods from the Reminder feature so the user can choose to automatically be
reminded about his/her Goal inputs at specific time intervals desired.
3.5. Food Recommendation Feature
The food recommendation mechanism is based on the manipulation of UniqueFoodList, via the implementation of the following operations:
-
Showing food recommendations as cards filtered by
Flagsand / orFood Names. -
Sorting the food list according to
SortOrderType. -
Showing combined recommendations from each food type with an additional Summary card.
-
Adding foods and Deleting foods
-
Resetting food database which clears modifications on the food list done by the user
These operations are respectively exposed in the Model interface as updateFilteredFoodList(), sortFoodList(), getMixedFoodList(), addFood(), deleteFood(), setFoods().
3.5.1. Data Structure Overview
It encapsulates FoodName, FoodType, and four NutritionValues and has the following usages:
-
Fields are visualized in
FoodCards, which collectively compose theFoodFlowPane. -
Fields are
Comparableto supportsortFoodList()function. -
NutritionValuesare used byFoodCalculatorto obtain summary statistics.
API: Food.java
It holds the collection of foods, and it exposes necessary methods in ModelManager.
Internally, it holds an ObservableList available for modifications, such as adding foods.
It also implements getMixedFoodList() method for recmfmix command via randomly selecting foods from its internalUnmodifiableList.
API: UniqueFoodList.java
The following class diagram summaries how these two main components interact.
Both Predicates, FoodNameContainsKeywordsPredicate and FoodTypeIsWantedPredicate hold desired conditions as Collections, such as List and Set.
They literate through the whole food list to select foods that matches any of given conditions.
If the conditions are empty, the test() result is always set to be true.
3.5.2. Implementation of recmf and recmfmix command
recmf command
RecmFoodCommandParser parses user inputs to standard parameters for the customised presentation of food recommendations, detailing in the following three ways:
Flags specify food types that are intended to be shown. This design is similar to using options in Unix commands.
Available Flags depend on available FoodTypes, as they will be eventually translated to a HashSet of FoodTypes and supplied to FoodTypeIsWantedPredicate.
If no flag is specified, RecmFoodCommandParser#getWantedFoodTypes(flagsStr) just returns an empty HashSet.
|
API: Flag.java; FoodType.java
It is similar to but simpler than the implementation of specifying flags. A List of food name strings will be supplied to FoodNameContainsKeywordsPredicate.
The following sequence diagram shows the how recmf command with flag and food name as the filters works.
The sorting related (refer to the following section) parts, such as FoodComparator, are omitted in this diagram.
|
It is implemented via supplying a FoodComparator to model#sortFoodList() method.
FoodComparator wraps A Comparator to handle the main logic, such as reversing the sorting order via Comparator#reversed().
An inner enum class SortOrderType holds all the comparable food fields for sorting.
The private FoodComparator constructor that directly takes in Comparator is for internal usage of getting reversed FoodComparator. Outside instantiation is done by supplying SortOrderType strings.
|
API: FoodComparator.java
recmfmix command
UniqueFoodList#getMixedFoodList() generates a temporary ObservableList from the existing food data. This list will eventually be supplied to FoodFlowPane via Model and then Logic.
-
Food Summary Card: It is essentially treated as
Foodwith Summary as food name and meal as food type. The total / average nutrition values are calculated byFoodCalculator.
This command has to override the Command#isToCreateNewPane() and return true,
since it must refresh the display pane each time by randomly getting new foods, rather than getting the existing display pane from typeToPaneMap (refer to MainDisplayPane.java).
|
API: FoodCalculator.java
3.5.3. Implementation of other supplementary commands
The following three commands can be used modify the food database.
addfood and deletef commands
AddFoodCommandParser and DeleteFoodCommandParser are used for parsing these two commands respectively.
Parameter validation is done by RecmFoodParserUtil.
resetf command
It is implemented by setting the internal list of UniqueFoodList to be the sample food data in SampleFoodDataUtil.
3.5.4. Example Usage Scenario and Summary
Given below is an example usage scenario and how the food recommendation mechanism behaves at each step.
-
The user launches the application and enter
recmf.-
If it is the first time entering a command, a
foodlist.jsonstorage file will be created with sample food data. Otherwise, data is loaded from the existing storage file. -
FoodFlowPaneobtains food list information fromLogicand displays food cards to the user.
-
-
The user executes
recmf -f -m +sort/gicommand.-
FoodTypeIsWantedPredicateis set to select foods of fruit and meal types.FoodComparatoris set to sort foods in ascending order based on their GI values. -
Modelupdates thefilteredFoodListwith this predicate and sorts the list with this comparator. -
FoodFlowPanenotices the such updates fromListenerand refreshes the GUI.
-
-
The user executes
recmfmixcommand.-
Logicgets a list of foods fromUniqueFoodList#getMixedFoodList(), which contains a Summary food calculated byFoodCalculator. -
FoodFlowPaneupdates its content with this new list.
-
-
The user executes
addfood fn/Cucumber ft/nsv ca/15 gi/15 su/1.7 fa/0.-
The display switches to show the full list which also contains this newly added food.
-
The storage file updates accordingly.
-
The following activity diagram summarizes the above steps.
3.5.5. Design Considerations
Aspect: Data Structure of the Food Collection
-
Alternative 1 (current choice): Use a
Listto store all the foods-
Pros: The logic can be easily understood.
-
Cons: Operations on foods, such as filtering and adding, need to iterating through the whole list.
-
-
Alternative 2: Use a
Mapthat categorizes foods based on their food types-
Pros: Impoves efficiency of filtering by flags by simply
get(). Besides, maintaining the order after adding a new food only requires to sort foods of the same type. It can improve efficiency especially when the database is large. -
Cons: There is no
FilteredMapclass supported by JavaFX. Extra work is needed to applyPredicateon the Map.
-
Aspect: The presentation (UI) of food recommendations
-
Alternative 1 (current choice): Show the user a pane of cards. Different types are indicated by the different colors.
-
Pros: Easy to implement. Cheerful colors may make reading more pleasant.
-
Cons: The size of food cards cannot be customized. If the window size is relatively small, the user may need to repeatedly scroll up and down to locate certain foods.
-
-
Alternative 2: Use several horizontal
ListViewsto hold different food type.-
Pros: The content can be more organized and the user does not need to specify the food types for filtering. Besides, the food cards can be customized for each
ListView, such as omitting GI and Sugar for proteins since they are usually zero. -
Cons: The operations targeting at the whole list need to be applied separately for each food list.
-
Aspect: Inputting New Food Data
-
Alternative 1 (current choice): Require inputs for all fields (e.g. calorie, gi…).
-
It prevents some foods from permanently having empty fields, which may result in inaccurate sorting and summaries.
-
Cons: There is no way to add new foods with currently unavailable fields.
-
-
Alternative 2: Use a separate list to hold foods with incomplete inputs.
-
Pros: This makes user inputs more flexible.
-
Cons: Extra work is needed to apply changes on two lists and transfer data from one list to the other.
-
3.5.6. Future Developments [Proposed Features]
-
Recovering data after resetting
[coming in v2.0]
This may be implemented by using a separate file to store the food data before executingresetfcommand. This file will be updated with the current food list before theresetfcommand is executed. -
Editing Foods
[coming in v2.0]
This can be adapted from exitingeditcommand fromAddressBook3. However, since foods are identified by names instead of indexes, may consider using aMapthat maps food names to food objects. -
Recording and Analyzing diets
[coming in v2.0]
This can be adapted from existingRecordmodel for daily, weekly, and monthly data summaries. The suggestions can be made via (1)calculating ideal nutrition value intake based the user’s BMI value, and (2) comparing the ideal intake amounts with the user’s actual intake amounts.
3.6. Logging
We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevelsetting in the configuration file (See Section 3.7, “Configuration”) -
The
Loggerfor a class can be obtained usingLogsCenter.getLogger(Class)which will log messages according to the specified logging level -
Currently log messages are output through:
Consoleand to a.logfile.
Logging Levels
-
SEVERE: Critical problem detected which may possibly cause the termination of the application -
WARNING: Can continue, but with caution -
INFO: Information showing the noteworthy actions by the App -
FINE: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
3.7. Configuration
Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).
4. Documentation
Refer to the guide here.
5. Testing
Refer to the guide here.
6. Dev Ops
Refer to the guide here.
Appendix A: Product Scope
Target user profile:
-
is diagnosed with type 2 diabetes
-
consults a professional health practitioner
-
has a need to manage a significant number of health-related records and tasks
-
is diligent in immediately recording events but subsequently forgets events
-
wants to gain a deeper understanding of his/her condition
-
is struggling with obesity
-
finds it difficult to get quick and customized suggestions about diets
-
is motivated by challenges
-
enjoys a personalised experience
-
needs to know his/her effectiveness in managing diabetes at a glance
-
prefer desktop apps over other types
-
can type fast
-
reads and writes competently in English
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: convenient all-in-one app for effectively managing diabetes that is faster than a typical mouse/GUI driven app
Appendix B: User Stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
|
diabetic patient who has different options on medical care |
know exactly how much I am spending on medication and consultation |
know which hospitals to seek medical care from |
|
very busy diabetic |
use a flexible calendar system that can account for updates |
easily make changes to appointments that I have to change often due to other commitments |
|
diabetic |
keep track of my medical expenses |
better manage my finance |
|
person who likes numbers |
see summary statistics |
better track my progress |
|
diabetic |
get an overview of my dieting/exercising data regularly |
save time because I am working 9-5 |
|
forgetful diabetic |
be reminded to attend my medical appointments |
know how well my existing measures work |
|
patient who has recently been diagnosed of diabetes |
be informed when I eat food with high sugar content |
live better and reduce the chances of further health deterioration |
|
lazy diabetic |
have reminders for exercising |
force myself to work out. |
|
busy diabetic |
be reminded on when to refill / stock up on insulin |
|
|
diabetic |
see graphical data summary |
minimise the need to read long paragraphs |
|
diabetic patient who has just been recently diagnosed |
have some motivation and reminders on my diet |
reduce my struggles of cutting down on meals or even exercise that is really tough for me |
|
diabetic |
automatically calculate my daily sugar/carb intake |
eliminate the trouble to search for the levels of sugar content in the food I eat everyday. |
|
diabetic who values my punctuality |
adhere to my appointment timings |
uphold my principles and take responsibility of my own health by not missing my appointments. |
|
diabetic |
reminded to take my insulin regularly |
|
|
diabetic |
be able to track my sugar levels |
|
|
task-oriented diabetic patient |
have a goal to work towards or a challenge to work on everyday |
have a sense of direction in what I can do to improve my health |
|
caretaker of an elderly patient with diabetes whose family members are busy working |
have a reliable app to keep track of all the patients' activities |
can answer to the family members who have entrusted unto me this responsibility of care |
|
busy person |
be able to easily sort and prioritize my tasks |
better manage my time |
|
diabetic patient who is often being referred to new doctors at different specialist clinics every now and then |
be able to be able to export all my records and activities at once |
rule out the possibility of missing any information during the registration process at a new clinic/ hospital I am visiting |
|
family member of a diabetic |
prioritize my tasks |
be immediately contactable if my family member has an emergency situation that requires urgent medical attention |
|
diabetic |
have a customisable app with avatars and different backgrounds |
enjoy a personalised experience |
|
lazy and obese individual |
be motivated constantly to exercise |
stop procrastinating |
|
forgetful diabetics patient |
have a record of my doctors' advice for each medical appointment and prescription directions |
better understand the steps that I can take to improve my condition until the next consultation |
|
achievement-oriented diabetic |
view the achievements and progress I have made on food intake |
remain motivated to keep my streak on good habits going |
|
paranoid diabetic who values privacy |
secure/encrypt my health data and other private contact details |
protect my data |
|
diabetic patient with a family |
have a user-friendly app that helps me manage my medical data and appointments on my own |
free the burden I have on my family |
|
diabetic patient with a family |
have a user-friendly app with natural commands that helps me manage my medical data and appointments on my own |
free the burden I have on my family |
|
diabetic patient in a community of diabetic patients |
have a standardised means of comparing our activities via a social network |
learn from my peers, encourage and be encouraged through this difficult journey. |
|
careless user |
undo my most recent actions |
easily make necessary amendments and input the correct commands |
|
a diabetic patient who has many medical receipts - and is not very good at mathematics |
have a simple calculator that is always easily accessible |
instantly calculate all my medical costs when needed |
|
an obese working adult at high risk of diabetes |
start monitoring my diet |
minimise my risk of having diabetes |
|
medical consultant |
export my patient’s health data |
save my time |
Appendix C: Use Cases
(For all use cases below, the System is the SugarMummy and the Actor is the user, unless specified otherwise)
Use case: Add blood sugar record
MSS
-
User requests to add a blood sugar record
-
System adds the blood sugar record
Use case ends.
Extensions
-
1a. The record is incomplete or passed invalid arguments.
-
1a1. System shows an error message.
Use case resumes at step 1.
-
Use case: Schedule a medical appointment
MSS
-
User requests to add a medical appointment
-
System adds the medical appointment
-
System notifies user of upcoming medical appointment beforehand
-
User acknowledges the notification and attends medical appointment on schedule
Use case ends.
Extensions
-
1a. The appointment is incomplete or passed invalid arguments.
-
1a1. System shows an error message.
Use case resumes at step 1.
-
-
3a. User snoozes the notification.
-
3a1. System waits for snooze time to elapse.
Use case resumes at step 3.
-
Use case: Delete blood sugar record
MSS
-
User requests list of blood sugar records
-
System shows a list of blood sugar records
-
User requests to delete a specific blood sugar record in the list
-
System deletes the blood sugar record
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. System shows an error message.
Use case resumes at step 2.
-
Use case: Recommend diabetes-friendly food
MSS
-
User requests for a diabetes-friendly food item
-
System shows a diabetes-friendly food item
-
User likes the recommendation
Use case ends.
Extensions
-
3a. User dislikes the recommendation.
-
3a1. User requests for another diabetes-friendly food item
Use case resumes at step 2.
-
Use case: Update blood sugar record
MSS
-
User requests list of blood sugar records
-
System shows a list of blood sugar records
-
User requests to update a specific blood sugar record in the list
-
System updates the blood sugar record
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. System shows an error message.
Use case resumes at step 2.
-
-
3b. The record is incomplete or passed invalid arguments.
-
3b1. System shows an error message.
Use case resumes at step 2.
-
C.1. Use case: Add a reminder
MSS
-
User requests to add a reminder
-
System adds the reminder
Use case ends.
Extensions
-
1a. The reminder already exists or the reminder is covered by existing reminder
-
1a1. System shows an error message.
Use case resumes at step 1.
-
-
1b. The reminder covers some other existing reminders
-
1b1. System removes the existing reminders covered by the new reminder
-
1b2. Use case resumes at step 2.
-
-
1c. The reminder and some existing reminders conflict
-
1c1. System shows an error message.
Use case resumes at step 1.
-
Appendix D: Non Functional Requirements
-
Should work on any mainstream OS as long as it has Java
11or above installed. -
Should be able to hold up to 1000 health-related records and tasks without a noticeable sluggishness in performance for typical usage.
-
A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
-
Third-party frameworks/libraries used should be free, open-source, and have permissive license terms, should not require any installation by the user of this software, and approved by teaching team.
-
Should work without requiring an installer.
-
The software should not depend on your own remote server
Appendix F: Instructions for Manual Testing
Given below are instructions to test the app manually.
| These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
F.1. Launch and Shutdown
-
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.
-
F.2. Saving Data
-
Dealing with missing data files
-
Prerequisite: Enter any valid command, such as
helporexit. -
Within the same directory of SugarMummy.jar, click the subfolder:
dataExpected: There are five json files of different lists. -
Delete any of the json file.
-
Enter any valid command, either in the same launch or a new launch of the jar file. Expected: In the
datafolder, a new json file corresponding to the missing one is created with sample data.
-
-
Dealing with corrupted data files
-
Prerequisite: Close the window. Otherwise, there is no effect of manually modifying the file since data are saved (overwritten) after every single command, including closing the window.
-
Access any json file in
datadirectory (Refer to Dealing with missing data files steps a and b). -
Use a text editor to randomly add or delete some lines in the json file and save it.
-
Re-launch the app and enter a command related to the modified json file. For example, if
foodlist.jsonis modified, enter 'recmf'.
Expected: A message indicating the list is empty will be shown.
-
F.3. Deleting a Record
-
Deleting a record while all records are listed
-
Prerequisites: List all records using the
listcommand. Multiple records in the list. -
Test case:
delete 1
Expected: First record is deleted from the list. Details of the deleted record shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No record is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete,delete x(where x is larger than the list size)
Expected: Similar to previous.
-
F.4. Average Command
-
Prerequisites: There are exactly 7 different days of blood sugar and exactly 7 different days of BMI records.
-
Test case:
average a/daily rt/bloodsugar
Expected: Shows a graph with 5 data points. The dates of the 5 data points are the 5 most recent blood sugar records. -
Test case:
average a/daily rt/bmi n/10
Expected: Since there are only 7 BMI records, the graph will only have 7 data points instead of 10. -
Test case:
average a/yearly rt/bmi n/3
Expected: This is an unsupported average type. An error message is displayed saying
Please enter correct input for a/AVERAGE_TYPE!.
AVERAGE_TYPE is "daily", "weekly" or "monthly" -
Test case:
average a/weekly
Expected: Missing compulsory field rt/RECORD_TYPE. An error message is shown:
Oops! The command you’ve entered appears to be in an invalid format.
average: Shows daily/weekly/monthly average of different record types in a line graph.
Format: average a/AVERAGE_TYPE rt/RECORD_TYPE [n/COUNT]
Example: average a/daily rt/bloodsugar n/5
-
-
Prerequisites: There are exactly 3 distinct weeks of blood sugar records and no BMI records.
-
Test case:
average a/weekly rt/bloodsugar
Expected: Since there are only 3 blood sugar records, the graph will only have 3 data points with dates of the 3 most recent blood sugar records in terms of week. There is not enough records to show 5 data points. -
Test case:
average a/weekly rt/bmi
Expected: Since there are no bmi records, an error message is displayed saying
Sorry! You do not have any BMI record.
-
-
Prerequisites: There are at least 12 distinct months of BMI records and no blood sugar records.
-
Test case:
average a/monthly rt/bmi n/9
Expected: Shows a graph with 9 data points and these points are the average BMI values of the 9 most recent month. -
Test case:
average a/monthly rt/expenses n/3
Expected: This is an unsupported record type. Following error message will be shown:
Please enter correct input for rt/RECORD_TYPE!
RECORD_TYPE is "BLOODSUGAR" or "BMI" -
Test case:
average a/monthly rt/bmi n/13
Expected: COUNT field is out of the range 1 and 12 inclusive. Following error message will be shown:
Please enter correct input for n/COUNT!
COUNT takes integer value between 1 and 12 inclusive. -
Test case:
average a/monthly rt/bmi n/five
Expected: COUNT field only takes integer value. Following error message will be shown:
Please enter correct input for n/COUNT!
COUNT takes integer value between 1 and 12 inclusive.
-
F.5. Achievement Commands
-
Test case:
achvm asdf
Expected: A error message is shown to the user indicating that the command cannot have any arguments.-
Prerequisites: There are at least 3 days worth of
BLOOSUGARrecords with a minimum of the past three days having consistent daily averages of 4.0 to 7.8 mmol/L ofBLOOSUGARlevel.
-
-
Test case:
achvm+ Expected:BRONZElevel achievement forBLOOSUGARis shown to beACHIEVEDin the achievements pane. Coloured image representing achievement is shown. -
Test case:
achVm+ Expected:BRONZElevel achievement forBLOOSUGARis shown to beACHIEVEDin the achievements pane. Theachvmcommand is not case-sensitive.-
Prerequisites: There are at least 2 days worth of
BLOOSUGARrecords with a minimum of the past two days having consistent daily averages of 4.0 to 7.8 mmol/L ofBLOOSUGARlevel.
-
-
Test case:
add rt/BLOODSUGAR dt/2019-11-06 12:12 con/4.5+ Expected: An achievement message is appended to the message showing successful addition of records in the feedback display pane, indicated the attainment of (an) achievement(s).BRONZElevel achievement forBLOOSUGARis shown to beACHIEVEDin the achievements pane whenachvmis entered.-
Prerequisites: There are EXACTLY 3 days of
BLOOSUGARrecords (one record per day) having consistent dailyBLOOSUGARlevels of 4.0 to 7.8 mmol/L.
-
-
Test case:
delete 3+ Expected: A message is appended to the successful records removal message indicating the loss of (an) achievement(s).BRONZElevel achievement forBLOOSUGARis no longer shown to beACHIEVEDin the achievements pane whenachvmis entered. Achievement state resets toYET TO ACHIEVEand image representing achievement can is in silhouette form again.-
Prerequisites: There are at least 3 days worth of
BLOOSUGARrecords with a minimum of the past three days having consistent daily averages of 4.0 to 7.8 mmol/L ofBLOOSUGARlevel. The last date ofBLOOSUGARrecords is on 2019-11-06.
-
-
Test case:
add rt/BLOODSUGAR dt/2019-11-07 12:12 con/4.5+ Expected:BRONZElevel achievement forBLOOSUGARcontinues to be shown to beACHIEVEDin the achievements pane ifachvmis entered.-
Prerequisites: There are at least 3 days worth of
BLOOSUGARrecords with a minimum of the past three days having consistent daily averages of 4.0 to 7.8 mmol/L ofBLOOSUGARlevel. The last date ofBLOOSUGARrecords is on 2019-11-06.
-
-
Test case:
add rt/BLOODSUGAR dt/2019-11-08 12:12 con/4.5+ Expected:BRONZElevel achievement forBLOOSUGARcontinues to be shown to bePREVIOUSLY ACHIEVEDin the achievements pane ifachvmis entered. Image representing achievement is gray-scaled and streak count resets to zero.-
Prerequisites: There are at least 3 days worth of
BLOOSUGARrecords with a minimum of the past three days having consistent daily averages of 4.0 to 7.8 mmol/L ofBLOOSUGARlevel. The last date ofBLOOSUGARrecords is on 2019-11-06.
-
-
Test case:
add rt/BLOODSUGAR dt/2019-11-07 12:12 con/7.9+ Expected:BRONZElevel achievement forBLOOSUGARcontinues to be shown to bePREVIOUSLY ACHIEVEDin the achievements pane ifachvmis entered. Image representing achievement is gray-scaled and streak count resets to zero.
F.6. Biography Commands
-
Prerequisites: NIL
-
Test case:
bio+ Expected: Existing biography pane with profile picture, fields and data. If no biography has been set, an empty biography containing a default profile picture will be shown. Fields showing background, background size/ repeat and font colour should not be affected whether or not there is a biography. If a field has no item, it should be an emptyString. -
Test case:
clrbio asdf
Expected: A error message is shown to the user indicating that the command cannot have any arguments.
-
-
Prerequisites: There is no existing biography.
-
Test case:
addbio n/test minimal p/91234567 e/81234567 m/test medical condition
Expected: A biography with updated fields name, phone, emergency contacts and medical condition is shown in the biography display pane. All other fields will remain blank. A message indicating success is displayed in the feedback display pane along with fields added. -
Test case:
addbio desc/hello world n/testName nric/testNric gender/testGender dob/1920-10-08 p/12343567 p/91234567 e/81234567 m/test medical condition a/example address 123 goal/testGoal o/testOtherInfo
Expected: A biography with entered fields is shown in the biography display pane. For listable fields (i.e. of prefix p/ e/ m/ g/), if more than one field is entered, the items will be presented in a numbered list in it’s cell of the biography table. A message indicating success is displayed in the feedback display pane along with fields added. -
Test case:
addbio n/firstTestName n/secondTestName p/91234567 e/81234567 m/test medical conditionExpected: An error message is displayed showing there cannot be more than one prefix for n/. -
Test case:
addbio n/firstTestName n/secondTestName gender/Male gender/Female p/91234567 e/81234567 m/test medical condition
Expected: An error message is displayed showing there cannot be more than one prefix for n/ and gender/ (displayed as the defaultStringrepresentation of a list to the user). -
Test case:
addbio n/name1 p/91234567 e/81234567 m/test medical condition
Expected: An error message is displayed showing names can only contain alphabets and spaces, and should not be blank. -
Test case:
addbio n/test minimal nric/@2 p/91234567 e/81234567 m/test medical condition
Expected: An error message is displayed showing NRICs can only contain alphanumeric characters and spaces, and should not be blank. -
Test case:
addbio n/test minimal p/91234567hi e/81234567 m/test medical condition
Expected: An error message is displayed showing that phone numbers should only contain numbers, and should be at least 3 digits long. -
Test case:
addbio n/test minimal p/91234567 e/81 m/test medical condition
Expected: An error message is displayed showing that phone numbers should only contain numbers, and should be at least 3 digits long. -
Test case:
addbio n/test minimal p/91234567 e/12345 m/test medical condition m/test medical condition
Expected: An error message is displayed showing that there are duplicate medical conditions found. -
Test case:
addbio n/ test minimal p/ 91234567 e/12345 m/test medical condition
Expected: Biography is added successfully with a message displayed to the user on fields added. Spaces in between fields do not affect parsing and spaces before arguments are automatically removed. Biography display pane is shown. -
Test case:
editbio n/test minimal
Expected: An error message is displayed to the user indicating that a bio does not exist and to suggest creating a new biography. -
Test case:
aDdBio n/test minimal p/91234567 e/81234567 m/test medical condition
Expected: A biography with updated fields name, phone, emergency contacts and medical condition is shown in the biography display pane. All other fields will remain blank. A message indicating success is displayed in the feedback display pane along with fields added. Capital letters in the command word do not affect the use of the program. -
Test case:
addbio N/test minimal p/91234567 e/81234567 m/test medical condition
Expected: An error message is displayed to the user as upper case fields are not recognised. -
Test case:
addbio n/test minimal p/91234567 e/81234567 m/test medical condition GENDER/male
Expected: Biography is added successfully butGENDER/malewill be appended rather than added as a field. -
Test case:
addbio m/test medical condition p/91234567 e/81234567 n/test minimal
Expected: Biography is added successfully with similar results as described above (for successful addition). Order of fields do not matter so long as command word is in front. -
Test case:
addbio m/test Medical Conditionp/91234567 e/81234567 n/test minimal
Expected: An error message is shown to the user as fields must be separated by a space and in this case, the field for contact number cannot be found. -
Test case:
addbio m/test Medical Conditionp/91234567 p/123 e/81234567 n/test minimal
Expected: Biography is added successfully butp/91234567is appended totest medical conditionas fields need to be separated by a space. -
Test case:
addbio m/test Medical Condition p/91234567 123 e/81234567 n/test minimal
Expected: An error message is shown to the user as phone numbers cannot contain a space. -
Test case:
clrbio
Expected: A error message is shown to the user that the biography is already empty and there is no biography to be cleared.
-
-
Prerequisites: There is an existing biography.
-
Test case:
addbio n/test Minimal p/91234567 e/81234567 m/test Medical Condition
Expected: An error message is displayed to the user indicating that a bio already exists and suggest clearing, editing or viewing the biography. -
Test case:
editbio n/Alan Wong
Expected: Name is sucessfully changed to Alan Wong in biography. Feedback displays the successful change and modified fields and biography display pane is shown. (if not already on the biography display pane) -
Test case:
editBio n/Alan Wong
Expected: Name is sucessfully changed to Alan Wong in biography. Feedback displays the successful change and modified fields and biography display pane is shown. (if not already on the biography display pane) Capital letters in the command do not affect parsing. -
Test case:
editBio N/Alan Wong
Expected: An error is shown to the user asN/is not recognised. Field prefixes are case-sensitive. -
Test case:
editbio n/Alan Wong p/12345678 p/234567
Expected: Fields are edited successfully. Feedback displays the successful change and modified fields. Previous list of phone numbers will be replaced by12345678and234567. -
Sub-prerequisite:
Alan Wongis already the name in the biography and phone number is12345678
Test case:editbio n/Alan Wong p/12345678
Expected: A message is indicated to the user indicating there is nothing to edit. -
Sub-prerequisite:
Alan Wongis already the name in the biography and phone number is NOT12345678
Test case:editbio n/Alan Wong p/12345678
Expected: Phone number is successfully replaced with12345678but modified fields in the feedback display will show only the change in name. -
Sub-prerequisite: There contains two or more emergency contact numbers.
Test case:editbio e/1/12345 e/2/23456
Expected: First and second existing emergency contact numbers in the list of emergency contact numbers will be replaced by the ones specified at index 1 and 2 respectively. Note that this should also similarly work for other listable fields such as Medical Conditions and Goals) -
Sub-prerequisite: There does NOT contain two or more emergency contact numbers.
Test case:editbio e/1/12345 e/2/23456
Expected: An error message is shown to the user that index is out of bounds. -
Test case:
editbio e/1/12345 e/23456
Expected: An error message is displayed to the user indicating that there is inconsistent indexing. -
Sub-prerequisite: There contains two or more emergency contact numbers and two or more goals.
Test case:editbio e/1/12345 e/2/3456 goal/first goal goal/second goal
Expected: Biography is edited successfully, with edited fields displayed in feedback display pane. Where there is more than one item edited for a field, they are displayed in theStringrepresentation of a list. Inconsistent indexing applies only if it is within a type of field (eg. emergency contacts in previous test case). -
Test case:
editbio n/Alan n/Amy
Expected: An error message is shown to the user that there can only be one prefix forn/(sinceNameis not aListableField) -
Test case:
editbio e/1/12345 e/-2/23456
Expected: An error message is shown to the user that index is invalid (since index cannot be negative). -
Test case:
editbio e/1/12345 e/hello/23456
Expected: An error message is shown to the user that index is invalid (since index cannot be a string). -
Test case:
editbio n/1/Amy
Expected: An error message is shown to the user that names can only contain alphabets and spaces and cannot be blank since this format for editing is not recognised for fields that do not inheritListableField. -
Test case:
editbio o/1/Amy
Expected: Biography is edited successfully but1/Amyis treated as aStringsince this format for editing is not recognised for fields that do not inheritListableField. -
Test case:
clrbio
Expected: A message indicates that the biography is successfully cleared and the user is shown the biography page with a default profile picture. All fields in the biography table should be blank except for the ones showing aesthetics (i.e.Background,Background Size,Background Repeat,Font Colour) -
Test action: Restart the application and enter
bio. Expected: Last set biography is loaded upon start up and displayed.
-
F.7. Aesthetics Commands
-
Prerequisites: Current font colour is NOT yellow and background colour (or dominant colour of background image) is dark (eg. not white)
-
Test case:
fontcolour yellow
Expected: Font colour is successfully changed to yellow. Colour changes instantaneously and applies to entire app. User is shown feedback that colour is changed from previous colour to "yellow" but the display pane that the user is on should not change. If the user is viewing the biography pane, theFont Colourfield changes instantaneously. -
Test case:
fontcolour #FFFF00
Expected: Font colour is successfully changed to yellow as described above. User is shown feedback that colour is changed from previous colour to "yellow" (as the colour is automatically converted) -
Test case:
fontcolOUr yeLlow
Expected: Font colour is successfully changed as described above as both commands and colours are not case sensitive. User feedback should indicate that colour is changed to "yellow". (always displayed in lower case) -
Test case:
fontcolOUr #FfFF00
Expected: Font colour is successfully changed as described above as both commands and colours are not case sensitive. Furthermore, there is automatic conversion of colour. User feedback should indicate that colour is changed to "yellow". -
Test case:
fontcolor yellow
Expected: Font colour is successfully changed as described above as the American spelling of "color" is also recognised. -
Test action: Restart the application Expected: Last set font colour is loaded upon start up.
-
-
Prerequisites: Current background colour (or dominant colour of background image) is NOT yellow and font colour is dark (eg. not white)
-
Test case:
bg yellow
Expected: Background colour is successfully changed to yellow. Colour changes instantaneously and applies to entire app. User is shown feedback that colour is changed from previous colour to "yellow" but the display pane that the user is on should not change. If the user is viewing the biography pane, theBackgroundfield changes instantaneously. -
Test case:
bg #FFFF00
Expected: Background colour is successfully changed to yellow as described above. User is shown feedback that colour is changed from previous colour to "yellow" (as the colour is automatically converted) -
Test case:
bG yeLlow
Expected: Background colour is successfully changed as described above as both commands and colours are not case sensitive. User feedback should indicate that colour is changed to "yellow". (always displayed in lower case) -
Test case:
Bg #FfFF00
Expected: Background colour is successfully changed as described above as both commands and colours are not case sensitive. Furthermore, there is automatic conversion of colour. User feedback should indicate that colour is changed to "yellow".
-
-
Prerequisites: Current font colour is NOT yellow and background colour (or dominant colour of background image) is close to yellow (eg. white)
-
Test case:
fontcolour yellow
Expected: Colour is not set and an error message is shown to the user indicating font colour is too close to background’s dominant colour. Feedback suggests for user to either change the background colour/ image first or simultaneously change both font colour and background together.
-
-
Prerequisites: Current background colour (or dominant colour of background image) is NOT yellow and font colour is close to yellow (eg. white)
-
Test case:
fontcolour yellow
Expected: Colour is not set and an error message is shown to the user indicating background colour (or dominant colour of background image) is too close to font colour. Feedback suggests for user to either change the font colour first or simultaneously change both background and font colour together.
-
-
Prerequisites: Current font colour is NOT #FF2020 and background colour (or dominant colour of background image) is NOT close to #FF2020 (eg. red)
-
Test case:
fontcolour FF2020
Expected: Font colour is successfully changed to yellow. Colour changes instantaneously. User is shown feedback that colour is changed from previous colour to "#FF2020" but the display pane that the user is on should not change. If the user is viewing the biography pane, theFont Colourfield changes instantaneously. Feedback indicates colour as #FF2020 as there is no CSS colour name assigned for this colour. -
Test case:
fontcolOUr #Ff2020
Expected: Font colour is successfully changed as described above as both commands and colours are not case sensitive. User feedback should indicate that colour is changed to "#FF2020". (always displayed in upper case)
-
-
Prerequisites: Background colour (or dominant colour of background image) is NOT #FF2020 and font colour is NOT close to #FF2020 (eg. red)
-
Test case:
bg #FF2020
Expected: Background is successfully changed to #FF2020. Colour changes instantaneously. User is shown feedback that colour is changed from previous colour to "#FF2020" but the display pane that the user is on should not change. If the user is viewing the biography pane, theFont Colourfield changes instantaneously. Feedback indicates colour as #FF2020 as there is no CSS colour name assigned for this colour. -
Test case:
bg #Ff2020
Expected: Background colour is successfully changed as described above as both commands and colours are not case sensitive. User feedback should indicate that colour is changed to "#FF2020". (always displayed in upper case)
-
-
Prerequisites: Current font colour is yellow
-
Test case:
fontcolour yellow
Expected: An error message is shown to the user indicating that the font colour is already the same as what was requested and thus there is nothing to be changed. -
Test case:
fontcolour `#FFFF00
Expected: An error message is shown to the user indicating that the font colour is already the same as what was requested and thus there is nothing to be changed.
-
-
Prerequisites: Current background colour is yellow
-
Test case:
bg yellow
Expected: An error message is shown to the user indicating that the background is already the same as what was requested and thus there is nothing to be changed. -
Test case:
bg `#FFFF00
Expected: An error message is shown to the user indicating that the background is already the same as what was requested and thus there is nothing to be changed.
-
-
Prerequisites: Current font colour is NOT yellow (background can be any colour but different from what it was previously)
-
Test case:
fontcolour yellow bg/black
Expected: Font colour is successfully changed to yellow as described above AND background is changed to black. Feedback message indicates both changes.
-
-
Prerequisites: Current background colour is NOT yellow (font colour can be any colour but different from what it was previously)
-
Test case:
bg yellow fontcolour/black
Expected: Background colour is successfully changed to yellow as described above AND font colour is changed to black. Feedback message indicates both changes.
-
-
Prerequisites: Current font colour is yellow (background can be any colour but different from what it was previously)
-
Test case:
fontcolour yellow bg/black
Expected: Font Colour is changed to black. Feedback message indicates that there is nothing to change for background and indicates the change in font colour.
-
-
Prerequisites: Current background colour is yellow (font colour can be any colour but different from what it was previously)
-
Test case:
bg yellow fontcolour/black
Expected: Background is changed to black. Feedback message indicates that there is nothing to change for fontcolour and indicates the change in background colour.
-
-
Prerequisites: Current font colour is NOT yellow and background colour is black.
-
Test case:
fontcolour yellow bg/black
Expected: Font colour is changed to yellow. Feedback message indicates change in font colour and that there is nothing to change for background colour.
-
-
Prerequisites: Current background colour is NOT yellow and font colour is black
-
Test case:
bg yellow fontcolour/black
Expected: Background colour is changed to yellow. Feedback message indicates change in background colour and that there is nothing to change for font colour.
-
-
Prerequisites: Current font colour is yellow and background colour is black.
-
Test case:
fontcolour yellow bg/black
Expected: Feedback message indicates that there is nothing to change.
-
-
Prerequisites: Current background colour is yellow and font colour is black.
-
Test case:
bg yellow fontcolour/black
Expected: Feedback message indicates that there is nothing to change.
-
F.8. Motivational Quotes Feature
-
Prerequisites: NIL
-
Test action: Restart the application
Expected: A new motivation quote is selected at random and shown in the pane showing motivational quotes at the bottom of the window.
-
F.9. Reminder and Event Command
-
Prerequisites: The calendar entry list is empty.
-
Test case:
reminder d/insulin inject dt/2019-11-30 17:00
Expected: Feedback message indicates that a new reminder: insulin inject On 2019-11-30 17:00 is added and the pane of all calendar entries shown. -
Test case:
reminder d/test dt/2019-12-10 12:00 r/daily
Expected: Feedback message indicates that a new reminder: test At 12:00 everyday From 2019-12-10 is added and the pane of all calendar entries shown. -
Test case:
event d/test dt/2019-12-01 11:00 dt/2019-12-01 11:30 td/01:00
Expected: Feedback message indicates that a new event: test From 2019-12-01 11:00 To: 2019-12-01 11:30 is added along with a new reminder for the event: Event: test in 1 hours 0 minutes On 2019-12-01 10:00. And the pane of all calendar entries shown. -
Test case:
event d/test dt/2019-12-01 11:00 dt/2019-12-01 10:00
Expected: Error message shown: The ending date time of an event should come after starting date time.
-
-
Prerequisites: The calendar entry list contains the following entries:
reminder: insulin inject On 2019-11-30 17:00
reminder: test At 12:00 everyday From 2019-12-10
event: test From 2019-12-01 11:00 To: 2019-12-01 11:30
reminder: Event: test in 1 hours 0 minutes On 2019-12-01 10:00
The following commands are typed in the order they present.-
Test case:
reminder d/insulin inject dt/2019-11-30 17:00
Expected: Error message shown: This reminder already exists in the calendar -
Test case:
reminder d/insulin inject dt/2019-11-30 17:00 r/daily
Expected: Feedback message indicates that a new reminder: insulin inject At 17:00 everyday From 2019-11-30 is added and the following reminder(s) were removed because they are covered by the new reminder: insulin inject On 2019-11-30 17:00. Also the pane of all all calendar entries shown. -
Test case:
reminder d/insulin inject dt/2019-12-20 17:00 r/weekly
Expected: Error message shown: This reminder is covered by insulin inject At 17:00 everyday From 2019-11-30. -
Test case:
reminder d/insulin inject dt/2019-11-20 17:00 r/weekly
Expected: Error message shown: This reminder and the following reminder(s) conflict: insulin inject At 17:00 everyday From 2019-11-30. -
Test case:
event d/test dt/2019-12-01 11:00 dt/2019-12-01 11:30
Expected: Error message shown: This event already exists in the calendar. -
Test case:
event d/test2 dt/2019-12-01 10:00 dt/2019-12-01 11:30
Expected: Feedback message indicates that a new event: test2 From 2019-12-01 10:00 To: 2019-12-01 11:30 is added. However, it overlaps with the following events: test From 2019-12-01 11:00 To: 2019-12-01 11:30.
-
F.10. Reminder list side pane
-
Prerequisites: The calendar entry list contains the following entries:
reminder: insulin inject At 17:00 everyday From 2019-11-30
reminder: test At 12:00 everyday From 2019-12-10
event: test From 2019-12-01 11:00 To: 2019-12-01 11:30
reminder: Event: test in 1 hours 0 minutes On 2019-12-01 10:00
reminder: test2 At 16:00 everyday From 2019-11-20
The user opens the app on 2019-12-11 15:00 and does not close it until 18:00.-
Expected: The side pane shows reminders that the user might miss today:
test at 12:00
At 16:00, a reminder of test2 is shown in the side pane. -
Test case:
reminder d/test3 dt/2019-12-11 16:30(typed in at 16:10)
Expected: At 16:30, a reminder of test3 is shown in the side pane.
At 17:00, a reminder of insulin inject is shown in the side pane.
-
F.11. Calendar Command
-
Prerequisites: The calendar entry list contains the following entries:
reminder: test At 12:00 everyday From 2019-12-10
event: test From 2019-12-01 11:00 To: 2019-12-01 11:30
The user opens the app on 2019-11-20-
Test case:
calendar
Expected: A pane of all the calendar entries added is shown. -
Test case:
calendar ym/2019-12
Expected: A monthly calendar of 2019 Dec is shown. Below are calendar entries on each day of 2019 Dec. In this case, there is a reminder of test at 12:00 listed in list for each day from Dec 10. An event of test from 11:00 to 11:30 is listed in Dec 1’s list. -
Test case:
calendar ymw/
Expected: A monthly calendar of 2019 Nov is shown. Below are calendar entries on each day from Nov 16 to Nov 22.
-
F.12. Food Recommendation Commands
-
Recommending food with specified flags
-
Test case:
recmf -f -p -m
Expected: The display pane updates food recommendations that only contain foods of fruit, protein, and meal, indicated by three different colors. -
Test case:
recmf -f -p -f -p -m -M
Expected: Same as a -
Test case:
recmf -p -f -mk
Expected: The main display pane remains unchanged. Message indicating this invalid format is shown. -
Test cases:
recmf fn/Chicken -f -sv
Expected: Foods that contain Chicken in their names is shown. Namely, after fn/ prefix, flags are treated as wanted food names.
-
-
Recommending food with specified food names
-
Test case:
recmf fn/rice cherry
Expected: Foods with food names that contain either rice and cherry are shown (case-insensitive). -
Test case:
recmf fn/
Expected: All available foods in the database are shown. -
Test case:
recmf fn/chicken fn/ fn/carrot
Expected: Foods with food names that contain carrot are shown. (The first two occurrences offn/are ignored.) -
Test case:
recmf fn/$#K
Expected: Message indicating no foods to recommend is shown. -
Test case:
recmf ft/
Expected: Message indicating this invalid format is shown.
-
-
Recommending food in specified order
-
Prerequisite: List all foods using the
recmfcommand. -
Test case:
recmf +sort/gi
..Expected: The food recommendations are refreshed in the order of ascending GI values. -
Test case:
recmf -sort/su
Expected: The food recommendations are refreshed in the order of descending sugar values. -
Test case:
recmf +sort/fa +sort/su
Expected: The ascending sort order is based on the last specification, namely, sugar. -
Test case:
recmf +sort/gi su
Expected: Message indicating invalid sorting order is shown. -
Test case:
recmf +sort/fa -sort/ca
Expected: Message indicating wrong presentation of both +sort/ and -sort/ is shown.
-
-
Recommending food combinations with sufficient foods in the database
-
Prerequisite: There are several foods of each type in the database.
-
Test case:
recmfmix
Expected: One food from each type is shown. A card named Summary is shown at the end with statistics from previous six foods. -
Test case:
recmfmixfor the second time
Expected: Similar to the scenario a but suggested foods are likely to be different. -
Test case:
recmfmix -p -s
Expected: Similar to scenario a. No effect of specifying flags.
-
-
Recommending food combinations with insufficient foods in the database
-
Prerequisite: The database has at least some foods but may lack foods of certain types.
-
Test case:
recmfmix
Expected: One food from available types is shown, in total maybe less than six. A Summary card is appended at the end as usual.
-
-
Recommending food combinations with no foods in the database
-
Test case:
recmfmix
Expected: Message indicating _no enough foods to recommend is shown. The Summary card is not shown.
-
-
Adding a new food with non-existing food name in the list
-
Test case:
addfood fn/Cucumber ft/nsv ca/15 gi/15 su/1.7 fa/0
Expected: This new food appears at the end of non-starchy vegetables. -
Test case:
addfood fn/Cucumber1 ft/f ca/15 gi/15 su/1. fa/.3
Expected: This new food appears at the end of fruits with sugar value of 1 and fat value of 0.3. -
Test case:
addfood fn/Cucumber2 ft/nsv f ca/15 gi/15 su/1.7 fa/0
Expected: Message indicating invalid food type is shown. -
Test case:
addfood fn/Cucumber3 ft/nsv ca/15 su/1.7 fa/0
Expected: Message indicating invalid format is shown. No updates on the display pane. -
Test case:
addfood fn/Cucumber4 ft/nsv ca/703 gi/15 su/1.7 fa/0
Expected: Message indicating too high value of Calorie is shown. -
Test case:
addfood fn/Cucumber5 ft/nsv ca/15 gi/15.99999 su/1.7 fa/0
Expected: Message indicating invalid nutrition value is shown.
-
-
Adding a new food with existing food name in the list
-
Prerequisite: A food named Cherry already exists in the food database.
-
Test case:
addfood fn/Cabbage ft/nsv ca/15 gi/15 su/1.7 fa/0
Expected: Message indicating food already existing is shown.
-
-
Deleting an existing food
-
Prerequisite: The given food names can be found in the food list.
-
Test case:
deletef fn/Mushroom
Expected: Mushroom is removed from recommendation display. -
Test case:
deletef fn/ Rice with Chicken
Expected: Rice with Chicken is removed from recommendation display. -
Test case:
deletef fn/cherry fn/carrotExpected: Carrot is removed from recommendation display. -
Test case:
deletef random fn/TomatoExpected: Message invalid command format is shown.
-
-
Deleting a non-existing food
-
Prerequisite: The given food names cannot be found in the food list.
-
Test case:
deletef fn/Beer
Expected: Message indicating food not found is shown.
-
-
Resetting foods
-
Test case:
resetfafterbio
Expected: The display pane switches to food recommendations. The full food list of default food data is shown. -
Test case:
resetfafterrecmf -p
Expected: The full food list of default food data is shown. -
Test case:
resetfafteraddfood fn/Cucumber ft/nsv ca/15 gi/15 su/1.7 fa/0Expected:Cucumbercard disappears in the food recommendations. -
Test case:
resetfafterdeletef fn/TomatoExpected:Tomatoappears in the food recommendations again.
-
Appendix G: References
G.1. Code References
-
https://stackoverflow.com/questions/11184117/transparent-css-background-color
-
https://stackoverflow.com/questions/12933918/tableview-has-more-columns-than-specified
-
https://stackoverflow.com/questions/49882605/javafx-italic-font-w-css
-
https://stackoverflow.com/questions/22952531/scrollpanes-in-javafx-8-always-have-gray-background
-
https://amyfowlersblog.wordpress.com/2010/05/26/javafx-1-3-growing-shrinking-and-filling/
-
https://medium.com/@keeptoo/adding-data-to-javafx-tableview-stepwise-df582acbae4f
-
https://self-learning-java-tutorial.blogspot.com/2018/06/javafx-tableview-adding-new-rows-to.html
-
https://stackoverflow.com/questions/39366828/add-a-simple-row-to-javafx-tableview
-
https://stackoverflow.com/questions/3342298/what-is-the-pattern-for-empty-string
-
https://www.geeksforgeeks.org/supplier-interface-in-java-with-examples/
-
https://howtodoinjava.com/regex/java-regex-date-format-validation/
-
https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html
-
https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java
-
https://stackoverflow.com/questions/29004893/transparent-node-background
-
https://stackoverflow.com/questions/9851200/setting-background-image-by-javafx-code-not-css
-
https://jutge.org/doc/java/docs/api/javafx/scene/doc-files/cssref.html
-
https://www.w3.org/TR/css-backgrounds-3/#the-background-repeat
-
https://stackoverflow.com/questions/6998551/setting-font-color-of-javafx-tableview-cells
-
https://stackoverflow.com/questions/1636350/how-to-identify-a-given-string-is-hex-color-format
-
https://stackoverflow.com/questions/4871051/getting-the-current-working-directory-in-java
-
https://stackoverflow.com/questions/7830951/how-can-i-load-computer-directory-images-in-javafx
-
https://www.inf.unibz.it/~calvanese/teaching/06-07-ip/lecture-notes/uni09/node12.html
-
https://stackoverflow.com/questions/924394/how-to-get-the-filename-without-the-extension-in-java
-
https://stackoverflow.com/questions/32639882/conditionally-color-background-javafx-linechart
-
http://java-buddy.blogspot.com/2012/05/create-borderpane-using-fxml.html
-
https://stackoverflow.com/questions/19512850/java-putting-hashmap-into-treemap
-
https://stackoverflow.com/questions/46170807/gridpane-change-grid-line-color
-
https://stackoverflow.com/questions/25168445/how-to-determine-if-color-is-close-to-other-color
-
https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java
-
https://stackoverflow.com/questions/3607858/convert-a-rgb-color-value-to-a-hexadecimal-string
-
https://stackoverflow.com/questions/10530426/how-can-i-find-dominant-color-of-an-image
-
https://blog.ngopal.com.np/2012/07/11/customize-scrollbar-via-css
G.3. References on Food Recommendations
G.4. Sources of Motivational Quotes
-
https://www.centralofsuccess.com/diabetes-slogans-quotes-funny-inspiring/
-
https://shortstatusquotes.com/inspirational-diabetes-status-quotes/
-
https://inspiringtips.com/healthy-diet-inspirational-quotes-weight-loss/
-
https://www.lifefitness.com.au/20-fitness-motivation-quotes/
-
https://www.inc.com/jayson-demers/51-quotes-to-inspire-success-in-your-life-and-business.html
-
https://www.stylecraze.com/articles/awesome-motivational-quotes-on-weight-loss/#gref
-
https://themighty.com/2016/12/chronic-illness-uplifting-quotes/
-
http://www.caringvoice.org/15-encouraging-quotes-chronic-illness-journey/
-
https://www.mindovermenieres.com/quotes-inspire-chronic-illness/
G.5. Credits for Images
-
Default User Profile Display Picture: Icon made by Smashicons (https://www.flaticon.com/authors/smashicons) from https://www.flaticon.com/free-icon/user_149068
-
Doge Profile Picture in User Guide Screenshot: https://pdxmonthly.com/articles/2015/1/5/who-let-the-doge-out-january-2015
-
Mountains Background Image in User Guide Screenshot: https://www.pexels.com/photo/landscape-photography-of-mountains-covered-in-snow-691668/
-
Space Background Image in User Guide Screenshot: Andy Holmes via https://unsplash.com/photos/LUpDjlJv4_c (with minor edits)
-
SugarMummy Logo: https://www.flaticon.com/authors/popcorns-arts