Skip to content

Commit

Permalink
Merge pull request #650 from EmilJunker/custom-body-stats
Browse files Browse the repository at this point in the history
Add support for custom body stats
  • Loading branch information
davidhealey authored Nov 11, 2022
2 parents 3fa4746 + d7a7567 commit af5b13b
Show file tree
Hide file tree
Showing 20 changed files with 541 additions and 62 deletions.
9 changes: 7 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,18 @@ sudo docker restart waistline_browser
To build for Android, you can use _android.Dockerfile_:
```sh
sudo docker build -t waistline:android -f ./docker/android.Dockerfile .
sudo docker run --rm -v $(pwd):/waistline/app/ --name waistline_android waistline:android
sudo docker run -v $(pwd):/waistline/app/ --name waistline_android waistline:android
```
If the build succeeded, you should find the APK under `./platforms/android/app/build/outputs/apk/debug/app-debug.apk`.

You can also launch the container interactively to execute your own commands:
```sh
sudo docker run -it --rm -v $(pwd):/waistline/app/ --name waistline_android waistline:android /bin/sh
sudo docker run -it -v $(pwd):/waistline/app/ --name waistline_android waistline:android /bin/sh
```

To start the container again after it stopped, use the `docker start` command:
```sh
sudo docker start -i waistline_android
```

We depend on an externally generated Docker image at the Android build. If you wish, you can build it locally in your repositories' directory by:
Expand Down
1 change: 1 addition & 0 deletions metadata/en-US/changelogs/30405.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- added ability to export diary as CSV file
- you can now customize the set of body stats you want to track
- your active goals are now listed separately on the Goals page
- improved Open Food Facts search integration
- carbs values of items imported from USDA no longer include fiber
Expand Down
12 changes: 12 additions & 0 deletions metadata/en-US/changelogs/30500.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- added ability to export diary as CSV file
- you can now customize the set of body stats you want to track
- your active goals are now listed separately on the Goals page
- improved Open Food Facts search integration
- carbs values of items imported from USDA no longer include fiber
- data gaps are now visible in the statistic chart
- added data sharing with external service (by default disabled -> developer settings)
- added support for Serbian language (Cyrillic and Latin)
- various bugfixes

You can find the full changelog at
https://github.com/davidhealey/waistline/releases
2 changes: 1 addition & 1 deletion www/activities/diary/js/diary-chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ app.DiaryChart = {
organiseData: function(data) {
return new Promise(async function(resolve, reject) {

const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits();
const visible = app.Settings.getField("nutrimentVisibility");
const showAll = app.Settings.get("diary", "show-all-nutriments");
Expand Down
37 changes: 29 additions & 8 deletions www/activities/diary/js/diary.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ app.Diary = {

this.getComponents();
this.bindUIActions();
this.setComponentVisibility();

let render = false;
let scrollPosition;
Expand Down Expand Up @@ -101,6 +102,21 @@ app.Diary = {
}
},

setComponentVisibility: function() {
const bodyStatsVisibility = app.Settings.getField("bodyStatsVisibility");
let logButtonVisible = false;

for (stat in bodyStatsVisibility) {
if (bodyStatsVisibility[stat] === true) {
logButtonVisible = true;
break;
}
}

if (!logButtonVisible)
app.Diary.el.log.style.display = "none";
},

resetReadyState: function() {
app.Diary.ready = false;
},
Expand Down Expand Up @@ -256,7 +272,7 @@ app.Diary = {
},

renderNutritionCard: async function(nutrition, date, swiper) {
const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits();
const energyUnit = app.Settings.get("units", "energy");

Expand Down Expand Up @@ -787,12 +803,14 @@ app.Diary = {

log: async function() {
const title = app.strings.diary["log-title"] || "Today's Stats";
const fields = app.measurements;
const fields = app.BodyStats.getBodyStats();
const internalUnits = app.BodyStats.getBodyStatsUnits();
const bodyStatsVisibility = app.Settings.getField("bodyStatsVisibility");

// Look for stats in the past 15 diary entries starting from the current date
const date = app.Diary.date;
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const stats = await app.Diary.getLastStats(d, 15);
const lastStats = await app.Diary.getLastStats(d, 15);

// Create dialog inputs
let inputs = document.createElement("form");
Expand All @@ -804,10 +822,10 @@ app.Diary = {
for (let i = 0; i < fields.length; i++) {
let x = fields[i];

if (x !== "weight" && !app.Goals.showInStats(x)) continue;
if (!bodyStatsVisibility[x]) continue;

let unit = app.Goals.getGoalUnit(x, false);
let value = app.Utils.convertUnit(stats[x], app.measurementUnits[x], unit, 100);
let value = app.Utils.convertUnit(lastStats[x], internalUnits[x], unit, 100);

let name = app.strings.statistics[x] || x;
let unitSymbol = app.strings["unit-symbols"][unit] || unit;
Expand All @@ -823,7 +841,8 @@ app.Diary = {
let title = document.createElement("div");
title.className = "item-title item-label";
title.innerText = app.Utils.tidyText(name, 50);
title.innerText += " (" + unitSymbol + ")";
if (unitSymbol !== undefined)
title.innerText += " (" + unitSymbol + ")";
inner.appendChild(title);

let inputWrap = document.createElement("div");
Expand Down Expand Up @@ -885,13 +904,15 @@ app.Diary = {
let entry = await app.Diary.getEntryFromDB() || app.Diary.getNewEntry();
let inputs = Array.from(dialog.el.getElementsByTagName("input"));

const internalUnits = app.BodyStats.getBodyStatsUnits();

let stats = {};

for (let i = 0; i < inputs.length; i++) {
let x = inputs[i];

let unit = app.Goals.getGoalUnit(x.id, false);
let value = app.Utils.convertUnit(parseFloat(x.value), unit, app.measurementUnits[x.id], 100);
let value = app.Utils.convertUnit(parseFloat(x.value), unit, internalUnits[x.id], 100);

if (!isNaN(value))
stats[x.id] = value;
Expand All @@ -910,7 +931,7 @@ app.Diary = {
const mealName = mealNames[category];
const dialogTitle = app.Utils.escapeHtml(app.strings.diary["default-meals"][mealName.toLowerCase()] || mealName);

const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits();
const energyUnit = app.Settings.get("units", "energy");
const visible = app.Settings.getField("nutrimentVisibility");
Expand Down
6 changes: 3 additions & 3 deletions www/activities/foods-meals-recipes/js/food-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ app.FoodEditor = {
/* Nutrition fields are dynamically created for the nutriments of the item */
renderNutritionFields: function(item) {

const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits(app.FoodEditor.scan == true);
const energyUnit = app.Settings.get("units", "energy");

Expand Down Expand Up @@ -525,7 +525,7 @@ app.FoodEditor = {
}

//Nutrition
const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
for (let k of nutriments) {
if (k != field) {
try {
Expand Down Expand Up @@ -655,7 +655,7 @@ app.FoodEditor = {
}

if (origin == "foodlist") {
const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits();
const energyUnit = app.Settings.get("units", "energy");
const inputs = document.querySelectorAll("#food-edit-form input:not(#barcode):not(#unit):not(#quantity), #food-edit-form textarea, #food-edit-form radio");
Expand Down
7 changes: 5 additions & 2 deletions www/activities/goals/js/goal-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ app.GoalEditor = {
app.GoalEditor.el.autoAdjustOption = document.querySelector(".page[data-name='goal-editor'] #adjust");
app.GoalEditor.el.minimumGoalOption = document.querySelector(".page[data-name='goal-editor'] #minimum");
app.GoalEditor.el.percentGoalOption = document.querySelector(".page[data-name='goal-editor'] #percent");
app.GoalEditor.el.showOptionsContainer = document.querySelector(".page[data-name='goal-editor'] #goal-show-options-container");
app.GoalEditor.el.showInDiary = document.querySelector(".page[data-name='goal-editor'] #show-in-diary");
app.GoalEditor.el.showInStats = document.querySelector(".page[data-name='goal-editor'] #show-in-stats");
app.GoalEditor.el.sharedGoal = document.querySelector(".page[data-name='goal-editor'] #shared-goal");
Expand Down Expand Up @@ -160,8 +161,10 @@ app.GoalEditor = {
},

hideShowComponents: function() {
if (app.measurements.includes(app.GoalEditor.stat)) {
app.GoalEditor.el.showInDiaryOption.style.display = "none";
const bodyStats = app.BodyStats.getBodyStats();

if (bodyStats.includes(app.GoalEditor.stat)) {
app.GoalEditor.el.showOptionsContainer.style.display = "none";
app.GoalEditor.el.sharedGoalOption.style.display = "none";
app.GoalEditor.el.autoAdjustOption.style.display = "none";
app.GoalEditor.el.minimumGoalOption.style.display = "none";
Expand Down
27 changes: 17 additions & 10 deletions www/activities/goals/js/goals.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,13 @@ app.Goals = {
app.Goals.el.yourList.innerHTML = "";
app.Goals.el.allList.innerHTML = "";

const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const units = app.Nutriments.getNutrimentUnits();
const energyUnit = app.Settings.get("units", "energy");
const measurements = app.measurements;
const stats = measurements.concat(nutriments);
const nutriments = app.Nutriments.getNutriments();
const bodyStats = app.BodyStats.getBodyStats();
const stats = bodyStats.concat(nutriments);

for (let x of stats) {
if ((x == "calories" || x == "kilojoules") && units[x] != energyUnit) continue;
if ((x == "calories" || x == "kilojoules") && app.nutrimentUnits[x] != energyUnit) continue;

let unit = app.Goals.getGoalUnit(x, true);
let unitSymbol = app.strings["unit-symbols"][unit] || unit;
Expand Down Expand Up @@ -89,12 +88,16 @@ app.Goals = {

getGoalUnit(stat, checkPercentGoal) {
const preferredUnits = app.Settings.getField("units") || {};
const units = app.Utils.concatObjects(app.Nutriments.getNutrimentUnits(), preferredUnits);
const nutrimentUnits = app.Nutriments.getNutrimentUnits();
const bodyStatsUnits = app.BodyStats.getBodyStatsUnits();
const units = app.Utils.concatObjects(nutrimentUnits, bodyStatsUnits);

if (stat == "body fat")
return "%";
if (app.measurements.includes(stat))
return (stat == "weight") ? units.weight : units.length;
if (stat == "weight")
return preferredUnits.weight
if (app.bodyStats.includes(stat))
return preferredUnits.length;
if (checkPercentGoal == true && app.Goals.isPercentGoal(stat))
return "%"
else
Expand Down Expand Up @@ -238,7 +241,9 @@ app.Goals = {
let statGoalValues = statGoal["goal"] || [];
let goal;

if (statGoal["shared-goal"] == true || app.measurements.includes(stat))
const bodyStats = app.BodyStats.getBodyStats();

if (statGoal["shared-goal"] == true || bodyStats.includes(stat))
goal = parseFloat(statGoalValues[0]);
else
goal = parseFloat(statGoalValues[day]);
Expand All @@ -257,8 +262,10 @@ app.Goals = {
let statGoalValues = statGoal["goal"] || [];
let averageGoal;

const bodyStats = app.BodyStats.getBodyStats();

if (statGoalValues.length) {
if (statGoal["shared-goal"] == true || app.measurements.includes(stat)) {
if (statGoal["shared-goal"] == true || bodyStats.includes(stat)) {
averageGoal = parseFloat(statGoalValues[0]);
} else {
let goalSum = statGoalValues.reduce((a, b) => parseFloat(a) + parseFloat(b));
Expand Down
2 changes: 1 addition & 1 deletion www/activities/goals/views/goal-editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
</div>

<div class="page-content">
<div class="list multi-line-titles">
<div id="goal-show-options-container" class="list multi-line-titles">
<ul>
<li id="diary">
<div class="item-content">
Expand Down
2 changes: 1 addition & 1 deletion www/activities/meals/js/meal-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ app.MealEditor = {
renderNutrition: async function() {
const nutrition = await app.FoodsMealsRecipes.getTotalNutrition(app.MealEditor.meal.items, "subtract");

const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits();

const ul = app.MealEditor.el.nutrition;
Expand Down
2 changes: 1 addition & 1 deletion www/activities/recipes/js/recipe-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ app.RecipeEditor = {
renderNutrition: async function() {
const nutrition = await app.FoodsMealsRecipes.getTotalNutrition(app.RecipeEditor.recipe.items, "subtract");

const nutriments = app.Settings.get("nutriments", "order") || app.nutriments;
const nutriments = app.Nutriments.getNutriments();
const units = app.Nutriments.getNutrimentUnits();

const ul = app.RecipeEditor.el.nutrition;
Expand Down
Loading

0 comments on commit af5b13b

Please sign in to comment.