FoodManager
and potentially even OptionalFood
if the latter is allowed to be passed around outside of FoodList
.
API: Ui.java
The UI
component makes use of the following classes:
Ui
: Responsible for communication between the other classes in the UI
component and with the Logic
component.UiHelper
: Responsible for providing helper methods to the other classes in the UI
component.UiInput
: Responsible for reading in the user commands and checking if it is empty.UiOuput
: Responsible for printing the outputs.UiMessage
: Responsible for storing output messages in methods so that they can be retrieved and printed when necessary.The UiMessage
class has dependencies with the following enumeration classes:
FitnessLevel
: Descriptions of the five FitnessLevel
are required in UiMessage#getAskForUserInfoMessage(String name)
as shown in the code snippet below.Gender
: Descriptions of the three Gender
are required in UiMessage#getAskForUserInfoMessage(String name)
as shown in the code snippet below.In summary, the UI
component,
Logic
component for command execution.Logic
component.Data of the user’s diet is stored in the app’s memory via the model: a FoodList
.
API: [FoodList.java
] (https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/list/FoodList.java)
FoodList
provides the following functions:
Additionally, it is not dependent on the other components listed. Instead, it is dependent on a common Food
class, which is used by serval components, including the storage, database, and calculator.
The above functions and the lack of dependency are met through the following means:
FoodList
stores new information added via the creation and maintenance of a list of FoodEntry
objects. These encapsulate the data being stored. In practice, the objects in the list are DatedFoodEntry
objects, which additionally support the storage of the date and time.FoodListManager
is used to perform logical operations on the list of FoodEntry
objects. A FoodManager
is also used as a fascade that obscures calculations and prevents modification of Food
data stored.String
that is meant to be supplied to the UI. In other data retrieval operations, such as those required by calculator, a list of Food
objects is supplied as a means of data transfer between the components. Other lists of java data types such as LocalDateTime
and Integer
are also provided to the storage component.Overall, FoodList
fulfils the role of being the app’s Model component by holding consumption data in the app’s memory. It is currently used as a singleton, but is not necessarily limited to such: e.g. a seperate FoodList
for favorites/recurrent entries or entries that are flagged as unhealthy/healthy can be made and maintained by Logic
.
There are a few common classes/packages that can be used multiple components. These are Food
, StringFormatter
, and MainLogger
, located in the seedu.dietbook.food
, seedu.dietbook.utils
, and seedu.dietbook.logger
packages respectively.
Food
is a data class containing all the relevant nutritional information on a food: calories, carbohydrates, proteins, fats. Being common to multiple components/classes, it is a means of data transfer between classes while reducing direct coupling.
StringFormatter
allows the formatting of strings in a manner similar to Python’s fstrings:
Strings can be formatted using the pattern ${map_key}
and a corresponding key to value map.
MainLogger
provides logging support to all classes.
This feature allows users to enter their personal information into the system so that they can be used for tracking diet progress and calorie recommendation calculation. This feature and its associated command words is only used during the initial setup of the application. Any subsequent editing of the user information can be done using the Edit user information feature.
Commands words used:
name
: Saves the user’s name or nickname into the application.info
: Saves the user’s age, gender, height, fitness level, original, current and target weight into the application.Main classes and methods used:
Manager
: Stores a Person
object.
Manager#setPerson(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, FitnessLevel newFitnessLevel)
: Calls a method in Person
class (listed below) to set the attribute values of the Person
object.Person
: Stores all user information provided.
Person#setAll(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, FitnessLevel newFitnessLevel)
: Updates the attribute values of the Person
object.Example usage scenario and how the feature work:
Summary: Only one instance of Person
is ever instantiated. A default person is instantiated at the start with default attribute values and when the user enters their information for the first time during the set up, all the default values would be updated to the inputted values. Therefore, the command to enter the user information will result in a change in the attribute values and not the creation of a new Person
object.
Step 1. When the user launches the application for the first time. A default Person
object will be initialised by Manager
and the user will be prompted to enter their name.
Object Diagram:
Step 2. The user inputs name Jack
command to enter their name into DietBook. The name
command calls Manager#setName(Jack)
, to store the name in Manager
first. After which, user will be prompted to enter all other details.
Object Diagram:
Sequence Diagram:
Step 3. The user inputs a command like the following info g/M a/21 h/175 o/85 c/85 t/75 f/2
to enter all other personal information including age, gender, height, fitness level, original, current and target weight. The info
command then calls Parse#executeProcessedInfo(info g/M a/21 h/175 o/85 c/85 t/75 f/2, manager)
before calling Manager#setPerson(Jack, Gender.MALE, 21, 175, 85, 85, 75, FitnessLevel.LOW)
which proceeds to call Person#setAll(Jack, Gender.MALE, 21, 175, 85, 85, 75, Fitness.LOW)
.
Object Diagram:
Sequence Diagram:
Aspect: Whether to enter name and other information separately or together
Aspect: Single or multiple usage of feature and command words
Aspect: Whether to use singleton pattern for Person class
Person
Person
object by mistake and there might be negative consequence in creating multiple objects.However, there is minimal risk of creating multiple Person
object by mistake and minimal negative consequence in creating multiple objects as long as the Manager
refers the correct instance of Person
.
Person
Person
object.Aspect: Changing attribute values in Person
object or creating new Person
object
Person
object
Person
object
Person
instance is kept and referred to.This feature allows users to edit their personal information after it has been entered into the system during the initial set up using the Enter user information feature. This feature was implemented to allow long term users to update their personal information like age, current weight, etc when necessary and also for careless users to edit their personal information if they have entered it wrongly.
Command word used:
editinfo
: Edits the user information stored in the application.editinfo a/22
: Edits the age of the user to 22
editinfo a/22 c/80
: Edits the age of the user to 22
and the current weight to 80
.editinfo n/Jane g/F a/22 h/165 o/70 c/63 t/60 f/3
: Edit the name, gender, age, height, original, current and target weight as well as the fitness level of the user to Jane
, female
, 22
,165
, 70
, 63
, 60
and You engage in moderate amount of exercise or have a job that requires moderate physical activity.
respectively.Main classes and methods used:
Person
: Stores all user information provided.
Person#setName(String newName)
: Updates the name the Person
object.Person#setGender(Gender newGender)
: Updates the gender of the Person
object.Person#setAge(int newAge)
: Updates the age of the Person
object.Person#setHeight(int newHeight)
: Updates the height of the Person
object.Person#setOriginalWeight(int newOriginalWeight)
: Updates the original of the Person
object.Person#setCurrentWeight(int newCurrentWeight)
: Updates the current weight of the Person
object.Person#setTargetWeight(int newTargetWeight)
: Updates the target weight of the Person
object.Person#setFitnessLevel(FitnessLevel newFitnessLevel)
: Updates the fitness level of the Person
objectExample usage scenario and how the feature work
Summary: The corresponding existing values in Person
class would be updated to the inputted values, even if the new value given is the same as the existing value.
Step 1. Takes for example the user’s name, age, gender, height, fitness level, original, current and target weight are currently Jack
, 21
, male
, 175
,You engage in some form of light exercise or have a job that requires some physical activity.
,85
, 85
and 75
respectively.
Object Diagram:
Step 2. When the user wishes to edit their age and current weight, they can enter a command like the following editinfo a/22 c/80
. The editinfo
command would call Parse#executeEditInfo(editinfo a/22 c/80, manager)
before Person#setAge(22)
and Person#setCurrentWeight(80)
is called.
Object Diagram:
Sequence Diagram:
Aspect: Whether one or more changes to the personal information can be made using a single command or through the use of various commands
Aspect: Use of multiple or single setter method(s)
Person
classPerson#setName(String newName)
: Updates the name the Person
object.Person#setGender(Gender newGender)
: Updates the gender of the Person
object.Person
class
Head over to the Design Considerations Section in the Enter user information feature for more related design considerations.
This feature allows users to view their personal information stored in system. It was implemented to allow users to validate their personal information so that they can edit it if necessary using the Edit user information feature.
Command word used:
userinfo
: Shows the user information stored in the application.Main classes and methods used:
Person
: Stores all user information provided.
Person#toString()
: Returns a string representation of all user information.Example usage scenario and how the feature work
Step 1. When the user wishes to view their personal information, they can enteruserinfo
. The
userinfo
command would call Person#toString()
.
Sequence Diagram:
This feature gives the user some flexibility, allowing them to make an entry without full knowledge of the nutritional information of the food that they are eating. Due to limitations in what can be estimated, there are only two main scenarios for missing fields: a missing total calorie count or some combination of missing nutritional values (carbohydrates, proteins, fat).
Main components involved:
Manager
: Parses the user input and creates an AddCommand
based on the details provided in the user input. It recognises that some combination of the optional inputs are missing and flags them to FoodList
when calling the FoodList#addFood(...)
method by using OptionalFood.EMPTY_VALUE = -1
as the input value.
FoodList
: A food entry is created via the FoodList#addFood(...)
method, which has some arguments set to OptionalFood.EMPTY_VALUE = -1
. Hence, when a FoodEntry
is instantiated, the FoodManager#createFood(String name, int calorie, int carbohydrate, int protein, int fat)
recognises the flags in the arguments and creates an OptionalFood
instead of Food
, for which a reference is kept in FoodEntry
. When a method requiring FoodEntry#getFood()
is called, FoodManager
is called via FoodManager#retrieveFood(Food food)
to return a Food
object with guesstimated nutritional values. This guesstimation process is done by the NutritionCalculator
class.
There are essentially two phases to the usuage of FoodManager
and its associated dependencies: the creation of a OptionalFood
that has missing values and the retrieval of a guesstimated Food
object when FoodEntry#getFood()
needs to be called.
For brevity, the focus will be on the processes within FoodList
.
Creation:
FoodList#addFood(int portionSize,String name, int calorie, int carbohydrate, int protein, int fat)
(or its variant for backlogs: FoodList#addFoodAtDateTime(...)
) is called by the Logic component to add a new entry with missing nutritional inputs. The missing inputs are encapsulated by OptionalFood.EMPTY_VALUE = -1
flags.FoodList#addFood(...)
instantiates a new instance of DatedFoodEntry
, passing on the arguments and flags to it instead. DatedFoodEntry
uses FoodManager#createFood(String name, int calorie, int carbohydrate, int protein, int fat)
to instantiate a Food
object. Because there are missing values, FoodManager
actually instantiates OptionalFood
, a child class of Food
instead. A reference to this OptionalFood
object is stored in the DatedFoodEntry
. The newly instantiated DatedFoodEntry
is also stored in the list of FoodEntry
objects in FoodList
.Retrieval:
FoodEntry#getFood()
is only called within functions of FoodListManager
. When a method such as FoodList#getPortionedFoods()
is called, FoodListManager#convertListToPortionedFoods(List list)
is subsequently called.FoodListManager#convertListToPortionedFoods(List list)
calls ListFunctions#applyFunctionToList(List list, Function function)
, and passes FoodEntry#getFood()
within the function argument.ListFunctions#applyFunctionToList(List list, Function function)
executes the function containing FoodEntry#getFood()
in its forEach
stream.FoodEntry#getFood()
calls the method FoodManager#retrieveFood(Food food)
, passing its Food
object as an argument.FoodManager#retrieveFood(Food food)
checks whether the Food
object is an instance of OptionalFood
. If it is an OptionalFood
, then it is handled differently based on the missing information. Otherwise, the Food
object is simply returned.OptionalFood
is calculated using NutritionCalculator
based on what is missing: if calorie is missing, then NutritionCalcular.calculateCalorieFromNutrients(int carbohydrate, int protein, int fat)
is called, otherwise NutritionCalculator.calculateNutrientsFromCalorie(int calorie, int carbohydrate, int protein, int fat)
is called instead to calculate the missing nutrient masses.Food
object containing the estimates is created and returned by FoodManager#retrieveFood(Food food)
, leaving the original reference to the Food
object in FoodEntry
unmodified in any case.Only simple methods of estimating the missing information is used by NutritionCalculator
. We can allow the user the weight the split of missing nutritional values differently (it is currently all weighed equally and split by calorie contribution). This ought to be performed by the Calculator
component since that is its main role. However, due to the fascade pattern being used in this implementation, the difficulty to add this feature is increased: in order to maintain the status of FoodList
being non-dependent on the other components, it is recommended that functions to split the nutrients be passed to FoodManager instead (i.e. use a functional paradigm).
Additionally, storage of the FoodList
should support the storage and retrieval of such missing values. Currently, only the estimated versions of the Foods are stored, and information on its status as a Food that had missing values (an OptionalFood
) is lost.
FoodManager
to obscure the details and processes behind the handling of a Food
object with missing values. It is noted that the OptionalFood
class is obscured in this process, despite being a child class of the common class Food
.
OptionalFood
or check for the possibility of missing values within Food
. This implementation limits the existence of instances of OptionalFood
to within the FoodEntry
class.FoodEntry
and FoodManager
had to be created and maintained due to the use of this design pattern. It also makes future work with other components that want to interact with FoodManager
more difficult (see Future Work section).FoodManager
could be exposed as a seperate set of API that should be invoked whenever an OptionalFood
needs to be handled. FoodManager
becomes an adapter that components such as FoodListManager
or other classes use when there is the possibility of an OptionalFood
object.
FoodManager
since it is exposed and can vary independently. It is also easier to test.FoodManager
and potentially even OptionalFood
if the latter is allowed to be passed around outside of FoodList
.The Save/Load feature is implemented by the saveload package.
At the base of the package, there is the Saver
and Loader
class.
Note only the Saver and Loader class is flexible. They can be adapted to new situations without modifying the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specifically for this version. They will have to be modified/replaced for future versions.
Stores data in a internal table with length and height specified. Handles the storage of its data by writing to a text file.
Specifies the length and height of the internal Saver table
Saver#save()
saves the current data to the file in the folder with the given file nameSaver#add()
Store String data in the x,y position in the tableLoads data from a text file and stores it in a internal table just like the saver
static method Loader.load(folder name , file name)
: creates a Loader object with
a table storing the data found in the text file
Loader#get()
retrives the data stored in the loaderBuilt on top of Saver and Loader class to implement save/load functionality
for list of food items the user has input into the dietbook. Contains a instance
of both Saver
and Loader
. It has its own folder to work with,
the user only has to specify the file name. To save the contents of a FoodList
, call
FoodPortionDateSaveLoadManager#saveFoodList(FoodList foodlist, String fileName)
To load a file, call FoodPortionDateSaveLoadManager#load()
first to load the contents of the file into
the FoodPortionDateSaveLoadManager
and then call FoodPortionDateSaveLoadManager#saveFoodList()
to
return the FoodList
with those contents.
FoodPortionDateSaveLoadManager#saveFoodList()
saves the contents of the FoodList
objectFoodPortionDateSaveLoadManager#load()
loads the file and store the contentsFoodPortionDateSaveLoadManager#saveFoodList()
returns a FoodList
with the contents of the ‘FoodPortionDateSaveLoadManager’Built on top of Saver and Loader class to implement save/load functionality for user information
Same as FoodPortionDateSaveLoadManager
, it has its own folder to work with, the user only has to specify the file name
Unlike the FoodPortionDateSaveLoadManager
, it stores the data inside itself and can be updated.
PersonSaveLoadManager#save()
save the current state into the filePersonSaveLoadManager#load()
loads the fileFoodPortionDateSaveLoadManager#save()
FoodPortionDateSaveLoadManager#load()
similiar diaghrams for PersonSaveLoadManager
DataBase
stores a list of food items that can be found in NUS and can be accessed by user
The data is organized into a Canteen contains a number of Stores each of which contains a list of food items
It also offers a number of filtering and searching methods. The data base resource is a text file which
can be manually updated.
Stores a List
of Canteen
objects. Each Canteen
object stores a List
of Store
object,
each Store
object contains a List
of Food
objects. Currently has a number of filtering and searching
methods. These methods can easily be modified and new ones implemented depending on the needs of the application.
DataBase#init()
reads from the data text resource and loads the contents into itselfDataBase#searchFoodByIndex()
returns the Food
with the provided indexDataBase#searchFoodByName()
returns the first Food
object that contains the string providedDataBase#searchAllFoodContainingName()
returns a Stream<Food>
that contains all Food
containing the string providedAs of this version, there is no dev mode for an administrator or a user to add new items to the data base. This can be done manually by directly editing the data.txt resource.
The DataBase#init()
method reads the data.txt file line by line
&%START and &%STOP the DataBase#init()
method will read anything between these two indicators
initially the data base is in the _*canteen*_
state, the next line it reads will be the canteen name
when it moves from the canteen name line to the next line, it is in the _*store*_
state,
again the next line it reads will be the store name, when it moves from the store name line to the next line,
now it is in the _*food*_
state. In this state, input a line in the format {food name}|{calorie}|{carbohydrate}|{protein}|{fats}
,
this will add a food item. Any number of food lines can be written and the database will be in the _*food*_
state.
To go back up to the store state, write a line of &%UP. If a store name is given in the next line, the database
will again be in the _*food*_
state. To go back up to the canteen state write 2 consecutive lines of &%UP.
|data.txt line|explanation|before state|after state| |—————————————————–|———————————————————–|—————–|—————| |&%START| starts the reading | not reading | canteen | | canteen1 | set the current canteen name to canteen1 | canteen | store | | store 1 | sets the current store name to store1 | store | food | | food1 | adds a food with the data of food1 | food | food | | food2 | adds a food with the data of food2 | food | food | | &%UP | goes up to store | food | store | | store 2 | sets the current store name to store2 | store | food | | food 3 | adds a food with the data of food3 | food | food | | &%UP | goes up to store | food | store | | &%UP | goes up to canteen | store | canteen | |&%STOP | stops the reading | canteen | not reading |
DataBase#init()
DataBase#search()
NUS students living on campus who would like to track their diet.
DietBook is designed to track the food and different kinds of nutritional intake of the user. It can also provide the user with a daily calorie recommendation based on their personal information. As the application mainly targets _NUS students staying on campus, it has a database prepopulated with food items commonly found around NUS. This allows for such food items to be easily added to the list of food items consumed for tracking.
Version | As a … | I want to … | So that I can … |
---|---|---|---|
v1.0 v2.0 | person with an ideal weight in mind | input my target weight and relevant information | get daily calorie intake recommendations |
v1.0 | careless or long term user | be able to view my personal information | make changes when necessary |
v2.0 | careless user | be able to edit my personal information | make changes if I input the wrong information |
v2.0 | potential long term user | be able to edit my personal information | make changes to information like age, weight and fitness level as it can changes over time |
v2.0 | user that wants to track weight changes | be able to view the weight I started off with, my current weight and the weight I desire | take note of my progress |
Java 11
is installed in the system.Given below are instructions to test the app manually.
name Tom and Jerry
Tom and Jerry
will be stored in the system and a message prompting the user to enter all other details will be displayed.name *1*
*1*
will be stored in the system and a message prompting the user to enter all other details will be displayed.name Ja/ck
nameJack
name
Name Jack
info g/M a/21 h/175 o/85 c/85 t/75 f/2
info o/85 a/21 f/2 h/175 g/M c/85 t/75
(where parameters can be entered in any order)info g/Ma/21h/175 o/85 c/85 t/75 f/2
(where there are no spaces between the different parameters)Info o/85 a/21 F/2 h/175 g/M c/85 t/75
(where any letter of the command word or parameter tags are capitalised)infog/M a/21 h/175 o/85 c/85 t/75 f/2
info g/M a/21 h/175 o/85 c/85 t/75 f/2 z/9
(where extra parameters,parameter tags or words are present)info g//F a/21 h/175 o/85 c/85 t/75 f/2
(where /
or any other special characters is used inappropriately)info g/f a/160 h/500 o/900 c/85 t/75.6 f/7
(where age, height, weights, gender and fitness level are not within the valid ranges or not valid - refer to User Guide for more information)info a/21
(where any of the required parameters are missing)editinfo n/Jane
Jane
.editinfo a/22 c/80
(where variable number of information is changed)22
while the current weight is updated to 80
.editinfo
Refer to Entering User Information Section under Instructions for manual testing for similar test cases that can be used for testing.
userinfo
userinfo userinfo
Userinfo