FitnessSheet
Backend
1. Variables
// function to convert time to millis
ensure var VarFunctionCalcTimeMillis kind: function
modules: ["MyFitnessPal"]
deploy: fixedOnDeploy
value: "function(dateString : text) : number
{
// Create a Date object with today's date and parsed time
const date = new Date(dateString);
// Get milliseconds since the epoch
const milliseconds = date.getTime();
return milliseconds;
}"
// types of activity
ensure var VarSetOfTextActivityType kind: setOfText
modules: ["MyFitnessPal"]
deploy: fixedOnDeploy
value: "<root>
<node key='keyFood'>Food</node>
<node key='keyWater'>Water</node>
<node key='keySleep'>Sleep</node>
<node key='keyExercise'>Exercise</node>
</root>"
// types of exercise
ensure var VarSetOfTextExerciseType kind: setOfText
modules: ["MyFitnessPal"]
deploy: fixedOnDeploy
value: "<root>
<node key='keyWalking'>Walking</node>
<node key='keyRunning'>Running</node>
<node key='keyGym'>Gym</node>
<node key='keyCycling'>Cycling</node>
<node key='keySwimming'>Swimming</node>
<node key='keyHiking'>Hiking</node>
</root>"
// function variable to calculate calorie burn
ensure var VarFunctionCalcCalorieBurn kind: function
modules: ["MyFitnessPal"]
deploy: fixedOnDeploy
value: "function(type : text, duration : number) : number
{
let calories = 0;
switch (type) {
case 'Walking':
calories = (duration/30) * 85;
break;
case 'Running':
calories = (duration/30) * 300;
break;
case 'Gym':
calories = (duration/30) * 150;
break;
case 'Cycling':
calories = (duration/30) * 330;
break;
case 'Swimming':
calories = (duration/30) * 215;
break;
case 'Hiking':
calories = (duration/30) * 250;
break;
default:
calories = null;
}
return calories;
}"
// function variable to calculate calorie gain
ensure var VarFunctionCalcCalorieGain kind: function
modules: ["MyFitnessPal"]
deploy: fixedOnDeploy
value: "function(size : number) : number
{
if (size >= 10 && size < 100)
{
return Math.floor(Math.random() * (100 - 10 + 1)) + 10;
}
else if (size >= 100 && size < 200)
{
return Math.floor(Math.random() * (200 - 100 + 1)) + 20;
}
else if (size >= 200 && size < 400)
{
return Math.floor(Math.random() * (400 - 200 + 1)) + 40;
}
else
{
return Math.floor(Math.random() * (800 - 400 + 1)) + 80;
}
}"
2. FitnessSheet
// fields ending with "*" suffix are required
ensure spreadsheet: FitnessSheet
withFields: [
"Date",
"Time*",
"Activity*"
]
ofTypes: [date, time, pickText]
modules: ["MyFitnessPal"]
readRoleSet: [Member]
insertRoleSet: [Member]
updateRoleSet: [Member]
removeRoleSet: [Member]
ensure form EntityFitness
modules: ["MyFitnessPal"]
ensure section: Details
ensure field Date defaultValue: "now"
ensure field Time defaultValue.value: now
ensure field Activity sourceVar: VarSetOfTextActivityType
ensure section: Water
ensure field Intake kind: number
helperText: "Water intake in ml"
suffix: "ml"
ensure section: Food
ensure field EnterManually kind: bool
showAsCheckbox: true
position: start
labelPlacement: end
ensure field FoodImage kind: image
ensure field RefFood kind: ref
spreadsheet: FoodItemMaster
layoutSpreadsheet: List
permissionMatrix: {
'defaultPermission': 'hide'
}
ensure field FoodName kind: text
ensure field AvgServingSize kind: number
permissionMatrix: {
'defaultPermission': 'invisible'
}
min: 0
ensure field Unit kind: pickText
permissionMatrix: {
'defaultPermission': 'invisible'
}
sourceVar: VarSetOfTextFoodItemUnit
ensure field Calories kind: number
permissionMatrix: {
'defaultPermission': 'invisible'
}
suffix: " cal"
min: 0
ensure field Protein kind: decimal
permissionMatrix: {
'defaultPermission': 'invisible'
}
min: 0.0
numberOfDigitsAfterPeriod: 2
ensure field Carbohydrate kind: decimal
permissionMatrix: {
'defaultPermission': 'invisible'
}
min: 0.0
numberOfDigitsAfterPeriod: 2
ensure field Fat kind: decimal
permissionMatrix: {
'defaultPermission': 'invisible'
}
min: 0.0
numberOfDigitsAfterPeriod: 2
ensure field ServingSize kind: number
ensure field TotalCalories kind: number
disabled: true
ensure field TotalProtein kind: decimal
disabled: true
numberOfDigitsAfterPeriod: 2
ensure field TotalCarbs kind: decimal
disabled: true
numberOfDigitsAfterPeriod: 2
ensure field TotalFat kind: decimal
disabled: true
numberOfDigitsAfterPeriod: 2
ensure section: Sleep
ensure field BedTime kind: label
ensure field From kind: dateTime
ensure field WakeUpTime kind: label
ensure field To kind: dateTime
ensure field TotalHours kind: number
ensure section: Exercise
ensure field ExerciseType kind: pickText sourceVar: VarSetOfTextExerciseType
ensure field Duration kind: number
helperText: "Exercise duration in minutes"
suffix: " min"
ensure field BurnedCalories kind: number
3. Fitness formula
// formula to calculate total calories gain
ensure formula TotalCalories
assignToField: Food.TotalCalories
formula: "let avgServing = ${f:AvgServingSize};
if(avgServing === undefined || avgServing === null)
{
${var:VarFunctionCalcCalorieGain}(${f:ServingSize})
}
else
{
((${f:ServingSize})/${f:AvgServingSize})*(${f:Calories})
}"
// formula, TotalProtien
ensure formula TotalProtien
assignToField: Food.TotalProtein
formula: "let avgServing = ${f:AvgServingSize};
if(avgServing === undefined || avgServing === null)
{
${f:TotalCalories}/4;
}
else
{
((${f:ServingSize})/${f:AvgServingSize})*(${f:Protein})
}"
// formula to calculate total fat
ensure formula TotalFat
assignToField: Food.TotalFat
formula: "let avgServing = ${f:AvgServingSize};
if(avgServing === undefined || avgServing === null)
{
${f:TotalCalories}/9;
}
else
{
((${f:ServingSize})/${f:AvgServingSize})*(${f:Fat})
}"
// formula to calculate total carbs
ensure formula TotalCarbs
assignToField: Food.TotalCarbs
formula: "let avgServing = ${f:AvgServingSize};
if(avgServing === undefined || avgServing === null)
{
${f:TotalCalories}/4;
}
else
{
((${f:ServingSize})/${f:AvgServingSize})*(${f:Carbohydrate})
}"
// formula to calculate total sleep hours
ensure formula TotalHours
assignToField: Sleep.TotalHours
formula: "if(${f:From}==null || ${f:To}==null)
{
null;
}
else
{
let fromDate = new Date(${f:From});
let toDate = new Date(${f:To});
let start = ${var:VarFunctionCalcTimeMillis}(fromDate);
let end = ${var:VarFunctionCalcTimeMillis}(toDate);
let ans = (end - start)/3600000;
ans
}"
// formula to calculate total calories burned
ensure formula BurntCalories
assignToField: Exercise.BurnedCalories
formula: "let ans = ${var:VarFunctionCalcCalorieBurn}(${f:ExerciseType.value}, ${f:Duration});
ans;"
4. Visibility rules
ensure visibilityRule FoodVisibilityRule
condition: "<root>
<stmt>Details.Activity == ${d:Activity.keyFood}</stmt>
</root>"
ensure actionMapIfTrue MakeFoodVisible
comp: Food
visibilityAction: visible
visibilityActionOn: component
ensure actionMapIfFalse MakeFoodHidden
comp: Food
visibilityAction: hidden
visibilityActionOn: component
// visibilityRule, WaterVisibilityRule
ensure visibilityRule WaterVisibilityRule
condition: "<root>
<stmt>Details.Activity == ${d:Activity.keyWater}</stmt>
</root>"
ensure actionMapIfTrue MakeWaterVisible
comp: Water
visibilityAction: visible
visibilityActionOn: component
ensure actionMapIfFalse MakeWaterHidden
comp: Water
visibilityAction: hidden
visibilityActionOn: component
// visibilityRule, ExerciseVisibilityRule
ensure visibilityRule ExerciseVisibilityRule
condition: "<root>
<stmt>Details.Activity == ${d:Activity.keyExercise}</stmt>
</root>"
ensure actionMapIfTrue MakeExerciseVisible
comp: Exercise
visibilityAction: visible
visibilityActionOn: component
ensure actionMapIfFalse MakeExerciseHidden
comp: Exercise
visibilityAction: hidden
visibilityActionOn: component
// visibilityRule, SleepVisibilityRule
ensure visibilityRule SleepVisibilityRule
condition: "<root>
<stmt>Details.Activity == ${d:Activity.keySleep}</stmt>
</root>"
ensure actionMapIfTrue MakeSleepVisible
comp: Sleep
visibilityAction: visible
visibilityActionOn: component
ensure actionMapIfFalse MakeSleepHidden
comp: Sleep
visibilityAction: hidden
visibilityActionOn: component
// visibilityRule, FoodManullyVisibilityRule
ensure visibilityRule FoodManullyVisibilityRule
condition: "<root>
<stmt>Food.EnterManually == ${d:EnterManually.true}</stmt>
</root>"
ensure actionMapIfTrue MakeRefFoodVisible
comp: Food.RefFood
visibilityAction: visible
visibilityActionOn: field
ensure actionMapIfTrue MakeFoodNameVisible
comp: Food.FoodName
visibilityAction: visible
visibilityActionOn: field
ensure actionMapIfTrue FoodImageHidden
comp: Food.FoodImage
visibilityAction: hidden
visibilityActionOn: field
ensure actionMapIfFalse MakeRefFoodHidden
comp: Food.RefFood
visibilityAction: hidden
visibilityActionOn: field
ensure actionMapIfFalse MakeFoodNameHidden
comp: Food.FoodName
visibilityAction: hidden
visibilityActionOn: field
ensure actionMapIfFalse MakeFoodImageHidden
comp: Food.FoodImage
visibilityAction: visible
visibilityActionOn: field
5. FitnessSheet layout
ensure spreadsheet FitnessSheet
ensure layoutSpreadsheet List kind: list
firstLine.first.lineFields: [Details.Date]
firstLine.middle.lineFields: [Details.Time]
firstLine.caption.lineFields: [Details.Activity]
// layoutSpreadsheet, table, WaterTable
ensure layoutSpreadsheet WaterTable kind: table
columnSizeSet: ["Flex"]
showComps: [Date, Time, Activity, Intake]
// layoutSpreadsheet, table, FoodTable
ensure layoutSpreadsheet FoodTable kind: table
columnSizeSet: ["Flex"]
showComps: [
Date,
Time,
Activity,
FoodName,
ServingSize,
TotalCalories,
TotalProtein,
TotalCarbs,
TotalFat
]
// layoutSpreadsheet, table, SleepTable
ensure layoutSpreadsheet SleepTable kind: table
columnSizeSet: ["Flex"]
showComps: [Date, Time, Activity, From, To, TotalHours]
// layoutSpreadsheet, table, ExerciseTable
ensure layoutSpreadsheet ExerciseTable kind: table
columnSizeSet: ["Flex"]
showComps: [Date, Time, Activity, ExerciseType, Duration, BurnedCalories]
Frontend
1. AddFitnessActivity
ensure action AddFitnessActivity kind: rowInsert
modules: ["MyFitnessPal"]
icon: "AddCircleOutlineRounded"
spreadsheet: FitnessSheet
sendMessageToInbox: true
2. AddWaterActivity
ensure action AddWaterActivity kind: rowInsert
icon: "AddCircleOutlineRounded"
modules: ["MyFitnessPal"]
defaultValueMap: {
'Details.Activity': {
'value': 'Water',
'optionId': 'keyWater'
}
}
spreadsheet: FitnessSheet
sendMessageToInbox: true
3. AddSleepActivity
ensure action AddSleepActivity kind: rowInsert
icon: "AddCircleOutlineRounded"
modules: ["MyFitnessPal"]
defaultValueMap: {
'Details.Activity': {
'value': 'Sleep',
'optionId': 'keySleep'
}
}
spreadsheet: FitnessSheet
sendMessageToInbox: true
4. AddExerciseActivity
ensure action AddExerciseActivity kind: rowInsert
icon: "AddCircleOutlineRounded"
modules: ["MyFitnessPal"]
defaultValueMap: {
'Details.Activity': {
'value': 'Exercise',
'optionId': 'keyExercise'
}
}
spreadsheet: FitnessSheet
sendMessageToInbox: true
5. AddFoodActivity
ensure action AddFoodActivity kind: rowInsert
icon: "AddCircleOutlineRounded"
modules: ["MyFitnessPal"]
defaultValueMap: {
'Details.Activity': {
'value': 'Food',
'optionId': 'keyFood'
}
}
spreadsheet: FitnessSheet
sendMessageToInbox: true
6. Prompts
//** prompt, PromptAddExerciseActivity
ensure prompt PromptAddExerciseActivity
modules: ["MyFitnessPal"]
action: AddExerciseActivity
promptText: "exercise ${f:ExerciseType}${sep}${f:Duration}"
permissionRoles: [Member]
//** prompt, PromptAddFoodActivity
ensure prompt PromptAddFoodActivity
modules: ["MyFitnessPal"]
action: AddFoodActivity
promptText: "food ${f:EnterManually}${sep}${f:RefFood}${sep}${f:ServingSize}"
permissionRoles: [Member]
//** prompt, PromptAddSleepActivity
ensure prompt PromptAddSleepActivity
modules: ["MyFitnessPal"]
action: AddSleepActivity
promptText: "sleep ${f:From}${sep}${f:To}"
permissionRoles: [Member]
//** prompt, PromptAddWaterActivity
ensure prompt PromptAddWaterActivity
modules: ["MyFitnessPal"]
action: AddWaterActivity
promptText: "water ${f:Intake}"
permissionRoles: [Member]
7. Group actions
ensure group MyFitnessPal
actionPermission: {
'AddFitnessActivity': {
'menuGroup': '1',
'roles': [
'Member'
]
},
'AddFoodActivity': {
'menuGroup': '1',
'roles': [
'Member'
]
},
'AddWaterActivity': {
'menuGroup': '1',
'roles': [
'Member'
]
},
'AddSleepActivity': {
'menuGroup': '1',
'roles': [
'Member'
]
},
'AddExerciseActivity': {
'menuGroup': '1',
'roles': [
'Member'
]
}
}