By: AY1920S2-CS2103-T09-4
Since: Feb 2020
Licence: MIT
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.
|
-
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
interface
with the same name as the Component. -
Exposes its functionality using a
{Component Name}Manager
class.
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 x/f i/1
.
delete x/f i/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
, ResultDisplay
, PagePane
, ButtonList
, CurrentPageTitle
etc.
Moreover, it reserves a place for different pages that can be filled and displayed.
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
Logic
component. -
Listens for changes to
Model
data so that the UI can be updated with the modified data.
2.3. Logic component
API :
Logic.java
-
Logic
uses theFitHelperParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding an entry). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
to 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 x/f i/1")
API call.
delete x/f i/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
The Model
,
-
stores a
UserPref
object that represents the user’s preferences. -
stores
UserProfile
andWeightRecords
objects for user’s personal information. -
stores the FitHelper data.
-
stores
FitHelperCommit
andVersionedFitHelper
objects for execution ofredo
andundo
instructions. -
exposes multiple unmodifiable
ObservableList<Entry>
and one unmodifiableObservableList<Diary>
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.
API : Model.java
Below are the class diagrams for different components of model
2.5. Storage component
API : Storage.java
The Storage
component,
-
saves a
UserPrefsStorage
object in json format and can read it back. -
saves a
FitHelperStorage
object in json format (fithelper.json) and can read it back. This database includes all data related to entries and diaries.-
FitHelperStorage
consists of lists ofEntry
andDiary
, and thus these two types of objects can be saved in json format and read back too.
-
-
saves a
UserProfileStorage
object in json format (userprofile.json) and can read it back. This database includes all data related to user profile attributes.-
UserProfileStorage
consists of a list ofProfile
, and objects in type ofProfile
can be saved in json format and read back.
-
-
saves a
WeightRecordsStorage
object in json format (weightrecords.json) and can read it back. This database includes all data related to weight records.-
WeightRecordsStorage
consists of a list ofWeight
, and objects in type ofWeight
can be saved in json format and read back.
-
2.6. Common classes
Classes used by multiple components are in the fithelper.commons
package.
3. Implementation
This section describes some noteworthy details on how certain features are implemented.
3.1. Entry Feature
The Entry consists of the following:
-
Each
Entry
consists of a unique combination ofName
,Calorie
,Location
,Duration
,Type
,Remark
,Status
andTime
-
Each
Entry
consists of aDuration
in hours, default set to 1, smallest accuracy is 0.02 (1 min). -
Each
Entry
consists of aType
, either food or sports -
Each
Entry
consists of aRemark
, default set to be empty -
Each
Entry
consists of aStatus
, eitherDone
orUndone
-
Each class has their respective getter methods
The class diagram below is an overview of the Entry
class.
3.1.1. Implementation of Entry Commands
Entry
class supports multiple commands. It includes:
-
AddCommand
- Adds aEntry
intoFitHelper
-
DeleteCommand
- Deletes aEntry
fromFitHelper
-
EditCommand
- Edits aEntry
fromFitHelper
-
FindCommand
- Finds allEntry
whosename
contains the keywords user entered -
ListCommand
- Lists allEntry
All the above entry commands will be parsed in FitHelperParser
and based on their
types (i.e Add, Delete, Edit etc), the corresponding parsers will be invoked (i.e AddCommandParser
,
EditCommandParser
etc). After which, the corresponding command will be executed (i.e AddCommand
,
EditCommand
etc).
The figure below shows the execution of an EditCommand
.
After a successful execution, the entry with the given index will be edited from FitHelper.
3.1.2. Design Considerations
Aspect: Type
for the entry
-
Option 1: As a string attribute in
Entry
-
Pros: Easy to implement, less code required
-
Cons: Provides a lower level of abstraction
-
-
Option 2: Use two different classes to represent types, such as
FoodEntry
andSportsEntry
-
Pros: Higher level of abstraction
-
Cons: More code, generic types are required for implementation of common functionality
-
In the end, we chose Option 1 as it reduces the amount of duplicated code required, given that all parameters of food entries and sports entries are the same. However, Option 2 is still an viable option.
Aspect: Time
for the entry
-
Option 1: Fix the format of
Time
to beyyyy-MM-dd-hh:mm
-
Pros: Easy to implement, less bug prone
-
Cons: Adds inconvenience to the user
-
-
Option 2: Use natty, the natural language date parser
-
Pros: Brings more convenience for CLI users
-
Cons: More bug prone due to the inaccuracy of the date parser. Moreover, only date can be parsed, not time.
-
Consequently, we chose Option 1 as it standardized the format of date and time across this application.
Aspect: Duration
for the entry
-
Option 1: As an optional attribute
-
Pros: More user friendly, since duration for food entry is less meaningful
-
Cons: Calendar display will not able to display food entries
-
-
Option 2: As an optional attribute, with default set to 1
-
Pros: Calendar display will not able to display food entries with no duration provided
-
Cons: The duration does not reflect the true value when user chooses not to enter
-
We chose Option 2 for better display of entries on the calendar
3.2. Today Feature
3.2.1. Implementation
FitHelper’s entries have a Time
attribute including a Date
and a specific Time
in the format of yyyy-mm-dd HH:mm
.
Today feature allows the user to view entries with the Date
of today, i.e. shows only entries in today.
It fetches the todayFoodEntries
and todaySportsEntries
stored in FitHelper storage. Because the display of these two lists
have the same logic, they are illustrated as todayEntries
in this section, as a whole.
-
In
FitHelper
, theUniqueEntryList<Entry> todayEntries
contains all entries on today. The list is updated whenever changes are made to the general UniqueEntryList<Entry> entries which contains entries of all dates. -
A
FilteredList<Entry> filteredTodayEntries
is stored in theModelManager
.filteredTodayEntries
in the ModelManager is initialized with thisUniqueEntryList<Entry>
by converting it to anObservableList<Entry>
. -
Today Page
takes intodayEntries
as a parameter when it is initialized. The list is always displayed on the GUI page as a ListView. -
When the
today
command is executed, FitHelper switches toToday Page
where the entries on today can be seen. -
Other features implemented in
Today Page
, likedaily calorie calculation
,daily task completion
, anddialy performance assessment
, all depend on the data carried by the passed in list.
An example usage scenario and how the today
mechanism behaves at each step is shown below.
Step 1. The user launches the application for the first time.
UniqueEntryList
will be initialized with a list of default entries in FitHelper, which contains a few entries with various dates.
UniqueTodayEntryList
will be initialized concurrently by filtering out entries on today.
Step 2. MainWindow
fetches ObservableList<Entry> todayEntries
.
Today Page
is initialized in MainWindow
with the ObservableList<Entry> todayEntries
passed from the model.
Step 3. The user inputs today
to view all today entries. UI
passes the input to Logic
.
Step 4. Logic passes the user input to FitHelperParser
. FitHelperParser
identifies that this is a TodayCommand
through the word "today".
It then creates a TodayCommandParser
to parse the it into a TodayCommand
and return.
Step 5. Logic
gets the TodayCommand
and execute it.
This execution then returns a CommandResult
to UI
, containing the success message and a specified displayed page of Today Page
.
Step 5. UI
displays the response in the CommandResult
.
UI
also switches FitHelper to Today Page
, where the continuously updated
todayEntryList
is displayed, since UI
is constantly listening for the change in Model
.
The Sequence Diagram below shows how the components interact with each other for the above mentioned scenario.
3.3. Diary Feature
3.3.1. Implementation
FitHelper also allows the user to keep a diary with a Date
in the format of yyyy-mm-dd
and the content
with no more than 200 characters.
The diaries are represented as model Diary
with the attributes of DiaryId
, DiaryDate
, and Content
.
This feature allows the user to view their diaries.
It fetches the filteredDiaryList
stored in FitHelper storage.
The diary feature is facilitated by
FilteredList
which wraps a ObservableList and
filters using the provided Predicate.
A FilteredList<Diary> filteredDiaries
is stored in the ModelManager
.
In FitHelper
, there is an
ObservableList<Diary> diaries
which contains all diaries, regardless of its DiaryDate
. filteredDiaries
in the ModelManager is initialized with this ObservableList.
Since a FilteredList needs a Predicate, which matches the elements in the source list that should be visible, the filter mechanism implements the following operation to support filtering:
-
Model#updateFilteredDiaryList(Predicate<Diary> predicate)
— Sets the value of the property Predicate in thefilteredDiaries
.-
The predicate is declared statically in the
Model
interface, namelyPREDICATE_SHOW_ALL_DIARIES
. In particularPREDICATE_SHOW_ALL_DIARIES
is as follows
-
Predicate<Diary> PREDICATE_SHOW_ALL_DIARIES = unused -> true;
-
The
DiaryCommand
will call this method to change the visibility of diaries with different status by passing in the corresponding predicate.
An example usage scenario and how the diary mechanism behaves at each step is shown below.
Step 1. The user launches the application for the first time.
UniqueDiaryList
contains no default diaries before the user adds any.
Step 2. The user inputs diary
to list all diaries. UI
passes the input to Logic
.
Logic then uses a few Parser
classes to extract layers of information out as seen from steps 3 to 5.
Step 3. Logic passes the user input to FitHelperParser
. FitHelperParser
identifies that this is a DiaryCommand
through the word "diary".
It then creates a
DiaryCommandParser
to parse the it into a DiaryCommand
and return.
Step 4. Logic
finally gets the DiaryCommand
and execute it.
The execution firstly calls
Model#updateFilteredDiaryList(Predicate<Diary> predicate)
to update the Predicate in
filteredDiaries
in Model
.
This execution then returns a CommandResult
to UI
, containing the response to the user.
Step 5. UI
displays the response in the CommandResult
.
In addition, UI will change to display diaries after model updates filteredDiaries
, since UI
is constantly listening for the change in Model
.
The Sequence Diagram below shows how the components interact with each other for the above mentioned scenario.
3.4. Undo/Redo feature
3.4.1. Implementation
The undo/redo mechanism is facilitated by VersionedFitHelper
.
It extends FitHelper
with an undo/redo history, stored internally as an fitHelperStateList
and currentStatePointer
.
Additionally, it implements the following operations:
-
VersionedFitHelper#commit()
— Saves the current FitHelper state in its history. -
VersionedFitHelper#undo()
— Restores the previous FitHelper state from its history. -
VersionedFitHelper#redo()
— Restores a previously undone FitHelper state from its history.
These operations are exposed in the Model
interface as Model#commit()
, Model#undo()
and Model#redo()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedFitHelper
will be initialized with the initial FitHelper state, and the currentStatePointer
pointing to that single FitHelper state.
Step 2. The user executes delete x/f i/5
command to delete the 5th food entry in the FitHelper. The delete
command calls Model#commit()
, causing the modified state of the FitHelper after the delete x/f i/5
command executes to be saved in the fitHelperStateList
, and the currentStatePointer
is shifted to the newly inserted FitHelper state.
Step 3. The user executes add x/f n/apple …
to add a new food entry. The add
command also calls Model#commit()
, causing another modified FitHelper state to be saved into the fitHelperStateList
.
If a command fails its execution, it will not call Model#commit() , so the FitHelper state will not be saved into the fitHelperStateList .
|
Step 4. The user now decides that adding the food entry was a mistake, and decides to undo that action by executing the undo
command. The undo
command will call Model#undo()
, which will shift the currentStatePointer
once to the left, pointing it to the previous FitHelper state, and restores the FitHelper to that state.
If the currentStatePointer is at index 0, pointing to the initial FitHelper state, then there are no previous FitHelper states to restore. The undo command uses Model#canundo() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
|
The following sequence diagram shows how the undo operation works:
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
The redo
command does the opposite — it calls Model#redo()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the FitHelper to that state.
If the currentStatePointer is at index fitHelperStateList.size() - 1 , pointing to the latest FitHelper state, then there are no undone FitHelper states to restore. The redo command uses Model#canRedo() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
|
Step 5. The user then decides to execute the command list
. Commands that do not modify the FitHelper, such as list
, will usually not call Model#commit()
, Model#undo()
or Model#redo()
. Thus, the fitHelperStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commit()
. Since the currentStatePointer
is not pointing at the end of the fitHelperStateList
, all FitHelper states after the currentStatePointer
will be purged. We designed it this way because it no longer makes sense to redo the add n/David …
command. This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
3.5. Calendar Feature
3.5.1. Implementation
-
The user enters a view command in the
calendar d/2020-04-13
. -
LogicManager
parses the user input, constructs and executes theCalendarCommand
. -
The
CalendarCommand
reachessetCalendarDate
,setCalendarMode
,setCalendarShow
in theModel
and returns theCommandResult
to theLogicManager
.-
Model#setCalendarDate()
— Set the referenced date for calendar, default set to current date. -
Model#setCalendarMode()
— Set the calendar display mode, can be eitherlist
orcalendar
mode. -
Model#setCalendarShow()
— Set the display of entries of a particular date, default set tonull
.
-
-
The
LogicManager
returns theCommandResult
to theUi
. -
The
Ui
gets theCommandResult
fromLogicManager
and updates the Ui to display the module. The following sequence diagram shows how the update operation works to change calendar page:
3.5.2. Design consideration
Aspect: Allowing no time clashes for all entries
-
Option 1: Allow multiple entries to exist over the same time period
-
Pros: More user friendly, since users might be doing multiple things for a given time period
-
Cons: Calendar display will not able to display food entries
-
-
Option 2: No time clashes allowed
-
Pros: Calendar display becomes clearer
-
Cons: Users are not given the freedom to add multiple entries with the same time period
-
We chose Option 1 for better display of entries on the calendar
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
logLevel
setting in the configuration file (See Section 3.7, “Add Weight Records”) -
The
Logger
for a class can be obtained usingLogsCenter.getLogger(Class)
which will log messages according to the specified logging level -
Currently log messages are output through:
Console
and to a.log
file.
Logging Levels
-
INFO
: Information showing the noteworthy actions by the App
3.7. Add Weight Records
FitHelper allows the user to track with their weight change easily by allowing user to add their current weight and previous weight.
3.7.1. Sample
An example usage scenario and how the addWeight
command behaves at each step is shown below.
Step 1.
-
The user launches the application for the first time.
-
UniqueWeightList
in Model contains no default weights before the user adds any. -
weightrecords.json
in local Storage contains no weight records as well.
Step 2.
-
The user inputs
addWeight
command word, followed byv/WEIGHT_VALUE
and an optionald/DATE
. -
UI
passes the input toLogic
. -
Logic
then uses a fewParser
classes to extract layers of information out as seen from steps 3 to 5.
Step 3.
-
Logic
passes the user input toFitHelperParser
. -
FitHelperParser
identifies that this is aAddWeightCommand
through the command word "addWeight". -
It then creates a
AddWeightCommandParser
to parse the input into aAddWeightCommand
and return back.
Step 4.
-
Logic
gets theAddWeightCommand
and execute it. -
The execution firstly check is the new weight date is after today’s date and if there is already a existing weight in the UniqueList.
-
Both of these two cases will throw corresponding
CommandException
. -
Then the execution add the new
Weight
into model. -
Finally, it returns a
CommandResult
toUI
, containing the response to the user and the displayPage, which equals toWEIGHT
page.
Step 5.
-
UI
displays the response in theCommandResult
. -
In addition, UI will change to display Weight Page after updating Profile Page and Weight Page.
3.7.2. Implementation
Storage
A weight is stored with three attributes in the weightrecords.json
database:
-
date
: the date of the weight record in format ofyyyy-MM-dd
, if no date is provided by the user, the default value is the date of today -
weightValue
: a double value with two decimal places. -
bmi
: the BMI value is also a double value with two decimal places. It is auto-computed and stored, using the formula :BMI = Weight Value(kg) / Height(m)^2
. The Height value gets from user profile inuserprofile.json
database.
Model
-
A single weight is represented as model
Weight
with the attributes ofDate
,WeightValue
, andBmi
. -
In
ModelManager
, all weights are represented byWeightRecords weightRecords
.-
The
WeightRecords
class implementsReadOnlyWeightRecords
interface, and therefore can return an unmodifiable version of a unique list of weights. -
The
WeightRecords
wraps aUniqueWeightList
which allows adding and iterating. Unique here refers to the constraint that no two weight with the same date can exist in the list/database.
-
-
In
ModelManager
, aFilteredList<Weight> filteredWeight
object is used to store and update a filtered version of all weights.-
The FilteredList wraps a
ObservableList
and filters using a providedPredicate
.
-
UI
When user input addWeight
command to UI
, the input is passed to Logic
part as a String
.
After addWeight
command is executed, a CommandResult
with DisplayPage
equals WEIGHT
will be passed back to MainWindow
in UI
part. Then:
-
Firstly, it will call
updateProfilePage()
, since if the newly added weight has the lasted date, Current Weight and Current BMI in uer profile will need to be updated. -
Secondly, it will call
updateWeightPage()
, since if a new weight is added successfully, new points should be added on to Weight Line Chart and BMI Line Chart. The text content of top notification will also be updated if the gap between Current Weight and Target Weight is changed. -
Lastly, it will call
showWeightPage()
. This allows the Main Window auto-switch to Weight Page after eachaddWeight
command by user.
Logic
The Sequence Diagram below shows how the components interact with each other for the mentioned scenario in sample.
3.8. Check calorie intake/consumption of some common food/sports
This function allows the user to search for calorie intake/consumption of food/sports by keywords. It helps the user better estimate how much calorie he/she will gain/burn by eating/exercising, so that he/she can add food/sports entry into the application without the need to search online for relevant information.
3.8.1. Implementation
The check function is achieved by calling the FitHelper
inside the ModelManager
to search
through either FoodCalorieTable
or SportsCalorieTable
for CalorieDatum
that contain the
keywords specified by the user.
Given below are example usage scenario:
Initialization: when the application is launched, ModelManager
will initialize a FitHelper
, which
will in turn initialize both FoodCalorieTable
and SportsCalorieTable
to contain pre-set data
which is a LinkedHashSet of one type of CalorieDatum
(either FoodCalorieDatum
or SportsCalorieDatum
).
Case 1: when the user enter the command check x/sports k/swim
, the LogicManager
will create
a CheckCommand
, which asks ModelManager
to let FitHelper
to search through SportsCalorieTable
to add first 3 CalorieDatum
whose name matches the keyword swim
into a set, and return the
set to CheckCommand
. Since the set contains at least one CalorieDatum
(meaning there is
some matching data), the CheckCommand
returns a CommandResult
whose feedbackToUser
contains a success message followed by the string representation of each matching datum.
Case 2: when the user enter the command check x/f k/swim
, the LogicManager
will create
a CheckCommand
, which asks ModelManager
to let ` FitHelper` to search through FoodCalorieTable
to add first 3 CalorieDatum`s whose name contains the keyword `swim
into a set, and return
the set to CheckCommand
. Since the set contains no CalorieDatum
(meaning there is no
matching data), the CheckCommand
returns a CommandResult
whose feedbackToUser
contains
a failure message followed by the string representation of the keyword.
The detailed searching mechanism is illustrated in the following activity diagram:
3.8.2. Design Considerations
Aspect: Data structure to store entries
-
Alternative 1 (current choice): Use an
LinkedHashSet
as a field in CalorieTable to store the entries.-
Pros: Easy to implement partial-key search (compare the keyword with the name of each entry in the set). Ensure that the database contains no duplicate data since a Set does allow duplicate elements.
-
Cons: O(n) complexity for finding matching entries, where n is the number of entries in the set.
-
-
Alternative 2: Use a
HashMap
as a field in CalorieTable to store the entries. The key is the name of the entry and the value is the entry.-
Pros: (theoretically) O(1) time complexity for finding an entry given a complete keyword, regardless of how many entries are in the HashMap.
-
Cons: hard to implement partial-key search (i.e. the keyword is only part of the name of the entry).
-
3.9. Store calorie data defined by the user [proposed in v2.0]
This proposed function allows the user to create his/her own calorie data and store them
into the application database. These data can be later searched by and shown to the user
via the existing check
command. This function helps the user to record calorie data of
food/sports not included in the pre-set database (or data more accurate than the ones
stored in the pre-set database), so that he/she do not need to remember these data
or search them online when he/she need to add same food/sports entry into the application
in the future.
3.9.1. proposed implementation
To store user-defined calorie data internally, we need current FitHelper class in
the Model component to associate 2 new classes UserFoodCalorieTable
and UserSportsCalorieTable
, which will store user-defined calorie
intake of food and calorie consumption of sports respectively.
To allow the application to access these user-defined data in the future, we need another class in the Storage component responsible for writing internally data into Json file and reading the Json file back to internally stored data when the user reopens the application.
To allow the check
command to search for user-defined data, the command will be modified to
retrieve data from UserFoodCalorieTable
or UserSportsCalorieTable
as well, depending
on the search type specified by the user.
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:
-
has a need to control weight, therefore need to record daily food intake and sports
-
prefer desktop apps over other types
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: achieve fitness control 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… |
---|---|---|---|
|
new user |
record my basic information such as name and gender |
have a more complete profile |
|
user who is concerned about body shape |
record and update my current height and weight |
have a clear view of my current body condition |
|
user who wants to lose weight |
set my target weight |
have a clear target to work towards |
|
user who wants to set diet plans |
add a food entry |
can plan my diet |
|
user who wants to control calorie intake |
view the calorie in each food entry |
can keep track of my calorie intake |
|
user who wants to set sports plans |
add a sport entry |
can plan for my sport exercises |
|
user who wants to increase calorie consumption |
view the calorie consumption for each sport entry |
can keep track of my calorie consumption |
|
user who wants to adjust my diet/sports plans |
edit a food/sports entry |
can have my plans and records updated |
|
user who wants to remove my diet/sports plans |
delete a food/sports entry |
|
|
user who wants to search for an entry |
search by keywords in the entry name |
can find related entries without having to scan through all the entries |
|
user who wants see today’s plans |
switch to Today Page and view the daily food/sports plans |
can have a general idea of the daily diet/sports arrangements |
|
user who needs some suggestions for my daily plan |
switch to Today Page and view FitHelper feedback |
I know whether my daily food/sports plan is suitable |
|
user who wants to know my daily performance |
switch to Today Page and view my performance report |
I know my food calorie intake distribution and my task completion |
|
user who types wrongly sometimes |
undo my previous command |
I do not need to delete explicitly using a long command |
|
user who types wrongly sometimes |
redo my previous undo command |
I can re-executed a undone command |
|
user who wants to keep a diary |
add a diary log for a specific day |
note down my schedules, feelings, goals and so on as a self-encouragement |
|
user who wants to append more content to a previous diary |
append new content to existing diaries |
enrich my previous diaries' content |
|
user who wants to replace the content of a previous diary with new content |
edit existing diaries |
modify the content to an updated version |
|
user who wants to remove some diary logs |
delete existing diaries |
keep abandon some diary logs that I do not want to keep |
|
user who wants to clear my diary |
clear all existing diaries |
I can re-start my diary from a white paper |
|
user who wants keep fit |
acknowledge my weight change trend according to time |
keep track of my weight change easily |
|
user who wants to lose weight |
compare between my current weight and target weight |
know the gap clearly |
|
user |
update my basic information such as address and name if necessary |
have an updated profile at any time |
|
user |
view pending tasks and status of daily calories goals in a calendar |
have cleaner display of data |
|
user who wants to have a clean user interface |
clear entries regularly |
do not need to see irrelevant information |
|
user |
leave the application when I need |
It does not occupy additional space in my computer |
|
user |
list all entries by certain criteria |
I can filter the tasks by what I am looking for |
|
user |
get reminders for tasks not done |
I can focused on these tasks and complete them |
|
user who do not know very well about dieting and exercising |
check calorie intake/consumption of common food and sports |
I can input calorie intake/consumption without having to search about these information online. |
|
first-time user |
view help page |
I can know the functions of the application quickly |
Appendix C: Use Cases
(For all use cases below, the System is the FitHelper
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Add an Entry
MSS
-
User adds an entry specifying a meal or a sport with name, time, location, and calorie.
-
FitHelper stores the entry to the specific date file.
-
FitHelper display successful record and the entry status.
Use case ends.
Extensions
-
1a. User input incomplete values.
-
1a1. FitHelper shows an error message.
Use case ends.
-
-
1b. The input time has clashes with previous entries.
-
1b1. FitHelper shows an error message.
Use case ends.
-
Use case: UC02 - Edits an Entry
MSS
-
User edits an entry specifying a meal or a sport with name, time, location, and calorie.
-
FitHelper modifies the entry to the specific date file.
-
FitHelper display successful record and the entry status.
Use case ends.
Extensions
-
1a. User input repeated values that are already stored in the entry.
-
1a1. FitHelper ignores the edit command.
Use case ends.
-
Use case: UC03 - Deletes an Entry
MSS
-
User deletes an entry by using the`delete` command.
-
FitHelper deletes the corresponding entry in the list and in the file.
-
FitHelper display the entry status and the successfully-delete message.
Use case ends.
Extensions
-
1a. The
INDEX
specified by the user does not exist.-
1a1. FitHelper shows an error message.
Use case ends.
-
{More to be added}
Appendix D: Non Functional Requirements
-
Should work on any mainstream OS as long as it has Java
11
or above installed. -
Should be able to hold up to 1000 entries without a noticeable sluggishness in performance for typical usage
-
Should be able to function normally without internet access.
-
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.
-
A user can get response from the system within 5 seconds after command input.
-
A user can be familiar with the system commands and interface within half an hour usage.
{More to be added}
Appendix E: Glossary
Prefix | Meaning | Used in the following Command(s) |
---|---|---|
x/ |
Type of entry |
add, check, delete, edit, find |
i/ |
Index of entry |
edit, delete, edit |
n/ |
Name |
add, edit |
t/ |
Time in format of "date hour minute" |
add, edit |
l/ |
Location |
add, edit |
c/ |
Calorie |
add, edit |
s/ |
Status |
add, edit |
r/ |
Remark |
edit |
d/ |
Date in format of yyyy-MM-dd |
calendar, addWeight |
dr/ |
Duration in format of yyyy-MM-dd yyyy-MM-dd |
add, edit |
dc/ |
Dairy contents |
dairy |
k/ |
Keyword |
check, find |
attr/ |
Attribute in user profile |
update |
v/ |
Attribute Value in user profile |
update, addWeight |
Command | Flag | Meaning |
---|---|---|
Sort |
-a |
Sort in ascending order |
Sort |
-d |
Sort in descending order |
Sort |
-t |
Sort according to time |
Sort |
-c |
Sort according to calorie intake |
Update |
-f |
Force update even with existing value |
Appendix F: Product Survey
Product Name : FitHelper
Author: …
Pros:
-
…
-
…
Cons:
-
…
-
…
Appendix G: 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. |
G.1. Launch and Shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the welcome page of FitHelper. On the left hand side, the user can see a list of page name. Users are able to click on the button or using corresponding command to direct to that page. -
The window size is fixed.
-
-
Shutdown
-
Users are able to shutdown the application using CLI with following commands:
-
exit
-
quit
-
bye
-
-
Users can also choose to shutdown the application by clicking on X button on the right top side if the window.
-
User data will be auto-saved if user choose to shutdown the application. Three local data file in json format can be find:
-
fithelper.json
: containg data related to entries and diaries. -
userprofile.json
: containing data related to user profile. -
weightrecords.json
: containing data related to all weight records.
-
-
G.2. Adding A New Weight Record
-
Add first weight record while there is no previous weight record in the database.
-
Prerequisites: None. Users are able to use
addWeight
command at any page. -
Test case:
addWeight v/50.0
Expected:-
A new
Weight
is added intoweightrecords
database, withWeightValue
equals 50.0,Date
with default value(today’s date) andBMI
calculated byHeight
. -
The window is automatically directed to weight page. A new point is shown on both Weight Line Graph and BMI Line Graph. The top notification is also updated.
-
In profile page, Current Weight and Current BMI change from "Not Available Now" to the newest value.
-
-
Test case:
addWeight v/49.0 d/2050-01-01
Expected: No new weight record is added since the date is after current date. An error message is shown in the command result box.
-
-
Add new weight record when there is already some previous weight records existing in the database.
-
Prerequisites: None. Users are able to use
addWeight
command at any page. -
Test case:
addWeight v/48.0
Expected: No new weight record is added since there is existing weight record with the same date (by default is today’s date) in the data base. An error message is shown in the command result box. -
Test case :
addWeight v/47.0 d/2020-03-01
Expected:-
A new
Weight
is added intoweightrecords
database, withWeightValue
equals 47.0,Date
with 2020-03-01 andBMI
calculated byHeight
. -
The window is automatically directed to weight page. A new point is shown on both Weight Line Graph and BMI Line Graph, and form a new trend line with previous data points. The top notification is also updated.
-
In profile page, Current Weight and Current BMI remain the same, since the newly added weight record is not the most recent record in the database.
-
-
G.3. Sorting entry lists
-
sort and display the entry lists stored in the sample FitHelper
-
Prerequisite: The data stored in FitHelper are the sample data. To restore to sample data, delete all files stored in the data folder and launch the application.
-
Test case:
sort by/time
Expected:-
The application will go to or remain at the dashboard page.
-
Entries in all three lists (Food Entry History, Sports Entry History and Reminders) are sorted by time in the descending order (entry with a later time comes first i.e. at top).
-
-
Test case:
sort x/s by/cal o/a
Expected:-
The application will go to or remain at the dashboard page.
-
Entries in Sports Entry History and Reminders list are sorted by calorie value in the ascending order (entry with a lower calorie value comes first i.e. at top).
-
Entries in Food Entry History list remain unchanged.
-
-
Test case:
sort x/s o/a
Expected:-
The application shows invalid command format error, followed by correct command format and example command in the bottom left corner.
-
-
G.4. Checking calorie data
-
search for calorie intake/consumption of common food/sports
-
Prerequisite: None, as long as the application is launched properly.
-
Test case:
check x/s k/swim
Expected:-
The application will go to or remain at the dashboard page.
-
The application shows calorie consumption per hour of common swimming styles in the bottom left corner.
-
-
Test case:
check x/f k/swim
Expected:-
The application will go to or remain at the dashboard page.
-
The application shows no matching results message in the bottom left corner.
-
-
Test case:
check k/swim
Expected:-
The application shows invalid command format error, followed by correct command format and example command in the bottom left corner.
-
-
G.5. Saving data
-
Dealing with missing/corrupted data files
-
If the application is launched and shut down at least once, there will be three local database in json format.
-
Delete
fithelper.json
, and launch FitHelper again. All user manipulation on entries and diaries will be cleared.Dashboard
,Today
,Calendar
andDiary
Page will restart with sample data. -
Delete
userprofile.json
, and launch FitHelper again. All user manipulation on user profile will be clear.Profile
page will restart with sample user data. -
Delete
weightrecords.json
, and launch FitHelper again. All user manipulation on weight records will be clear.Profile
page will show Current Weight and Current BMI as "Not Available Now", andWeight
Page will have no data point on the trend line graph.
-