1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-13 12:14:19 +02:00

added TDEE and calories measurement and change BMR to Harris-Benedict equation

This commit is contained in:
oliexdev
2019-01-06 18:00:48 +01:00
parent f27dfbd514
commit ed60b2478d
23 changed files with 514 additions and 30 deletions

View File

@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "974ad0a810bf389300cf67b40862bb75",
"identityHash": "2db259b9e244ebad0c664f2c9fb36068",
"entities": [
{
"tableName": "scaleMeasurements",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `datetime` INTEGER, `weight` REAL NOT NULL, `fat` REAL NOT NULL, `water` REAL NOT NULL, `muscle` REAL NOT NULL, `visceralFat` REAL NOT NULL, `lbm` REAL NOT NULL, `waist` REAL NOT NULL, `hip` REAL NOT NULL, `bone` REAL NOT NULL, `chest` REAL NOT NULL, `thigh` REAL NOT NULL, `biceps` REAL NOT NULL, `neck` REAL NOT NULL, `caliper1` REAL NOT NULL, `caliper2` REAL NOT NULL, `caliper3` REAL NOT NULL, `comment` TEXT, FOREIGN KEY(`userId`) REFERENCES `scaleUsers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `datetime` INTEGER, `weight` REAL NOT NULL, `fat` REAL NOT NULL, `water` REAL NOT NULL, `muscle` REAL NOT NULL, `visceralFat` REAL NOT NULL, `lbm` REAL NOT NULL, `waist` REAL NOT NULL, `hip` REAL NOT NULL, `bone` REAL NOT NULL, `chest` REAL NOT NULL, `thigh` REAL NOT NULL, `biceps` REAL NOT NULL, `neck` REAL NOT NULL, `caliper1` REAL NOT NULL, `caliper2` REAL NOT NULL, `caliper3` REAL NOT NULL, `calories` REAL NOT NULL, `comment` TEXT, FOREIGN KEY(`userId`) REFERENCES `scaleUsers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@@ -128,6 +128,12 @@
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "calories",
"columnName": "calories",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "comment",
"columnName": "comment",
@@ -247,9 +253,10 @@
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"974ad0a810bf389300cf67b40862bb75\")"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"2db259b9e244ebad0c664f2c9fb36068\")"
]
}
}

View File

@@ -0,0 +1,262 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "2db259b9e244ebad0c664f2c9fb36068",
"entities": [
{
"tableName": "scaleMeasurements",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `datetime` INTEGER, `weight` REAL NOT NULL, `fat` REAL NOT NULL, `water` REAL NOT NULL, `muscle` REAL NOT NULL, `visceralFat` REAL NOT NULL, `lbm` REAL NOT NULL, `waist` REAL NOT NULL, `hip` REAL NOT NULL, `bone` REAL NOT NULL, `chest` REAL NOT NULL, `thigh` REAL NOT NULL, `biceps` REAL NOT NULL, `neck` REAL NOT NULL, `caliper1` REAL NOT NULL, `caliper2` REAL NOT NULL, `caliper3` REAL NOT NULL, `calories` REAL NOT NULL, `comment` TEXT, FOREIGN KEY(`userId`) REFERENCES `scaleUsers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "enabled",
"columnName": "enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dateTime",
"columnName": "datetime",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "weight",
"columnName": "weight",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "fat",
"columnName": "fat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "water",
"columnName": "water",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "muscle",
"columnName": "muscle",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "visceralFat",
"columnName": "visceralFat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lbm",
"columnName": "lbm",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "waist",
"columnName": "waist",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "hip",
"columnName": "hip",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "bone",
"columnName": "bone",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "chest",
"columnName": "chest",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "thigh",
"columnName": "thigh",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "biceps",
"columnName": "biceps",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "neck",
"columnName": "neck",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "caliper1",
"columnName": "caliper1",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "caliper2",
"columnName": "caliper2",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "caliper3",
"columnName": "caliper3",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "calories",
"columnName": "calories",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "comment",
"columnName": "comment",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_scaleMeasurements_userId_datetime",
"unique": true,
"columnNames": [
"userId",
"datetime"
],
"createSql": "CREATE UNIQUE INDEX `index_scaleMeasurements_userId_datetime` ON `${TABLE_NAME}` (`userId`, `datetime`)"
}
],
"foreignKeys": [
{
"table": "scaleUsers",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"userId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "scaleUsers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `username` TEXT NOT NULL, `birthday` INTEGER NOT NULL, `bodyHeight` REAL NOT NULL, `scaleUnit` INTEGER NOT NULL, `gender` INTEGER NOT NULL, `initialWeight` REAL NOT NULL, `goalWeight` REAL NOT NULL, `goalDate` INTEGER, `measureUnit` INTEGER NOT NULL, `activityLevel` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userName",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "birthday",
"columnName": "birthday",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "bodyHeight",
"columnName": "bodyHeight",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "scaleUnit",
"columnName": "scaleUnit",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gender",
"columnName": "gender",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "initialWeight",
"columnName": "initialWeight",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "goalWeight",
"columnName": "goalWeight",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "goalDate",
"columnName": "goalDate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "measureUnit",
"columnName": "measureUnit",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "activityLevel",
"columnName": "activityLevel",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"2db259b9e244ebad0c664f2c9fb36068\")"
]
}
}

View File

@@ -135,7 +135,7 @@ public class OpenScale {
db.setForeignKeyConstraintsEnabled(true);
}
})
.addMigrations(AppDatabase.MIGRATION_1_2, AppDatabase.MIGRATION_2_3)
.addMigrations(AppDatabase.MIGRATION_1_2, AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4)
.build();
measurementDAO = appDB.measurementDAO();
userDAO = appDB.userDAO();

View File

@@ -16,17 +16,17 @@
package com.health.openscale.core.database;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.room.Database;
import androidx.room.RoomDatabase;
import androidx.room.TypeConverters;
import androidx.room.migration.Migration;
import com.health.openscale.core.datatypes.ScaleMeasurement;
import com.health.openscale.core.datatypes.ScaleUser;
import com.health.openscale.core.utils.Converters;
@Database(entities = {ScaleMeasurement.class, ScaleUser.class}, version = 3)
import androidx.room.Database;
import androidx.room.RoomDatabase;
import androidx.room.TypeConverters;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
@Database(entities = {ScaleMeasurement.class, ScaleUser.class}, version = 4)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
public abstract ScaleMeasurementDAO measurementDAO();
@@ -130,4 +130,50 @@ public abstract class AppDatabase extends RoomDatabase {
}
}
};
public static final Migration MIGRATION_3_4 = new Migration(3, 4) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.beginTransaction();
try {
// Drop old index
database.execSQL("DROP INDEX index_scaleMeasurements_userId_datetime");
// Rename old table
database.execSQL("ALTER TABLE scaleMeasurements RENAME TO scaleMeasurementsOld");
// Create new table with foreign key
database.execSQL("CREATE TABLE scaleMeasurements"
+ " (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
+ " userId INTEGER NOT NULL, enabled INTEGER NOT NULL,"
+ " datetime INTEGER, weight REAL NOT NULL, fat REAL NOT NULL,"
+ " water REAL NOT NULL, muscle REAL NOT NULL, visceralFat REAL NOT NULL,"
+ " lbm REAL NOT NULL, waist REAL NOT NULL, hip REAL NOT NULL,"
+ " bone REAL NOT NULL, chest REAL NOT NULL, thigh REAL NOT NULL,"
+ " biceps REAL NOT NULL, neck REAL NOT NULL, caliper1 REAL NOT NULL,"
+ " caliper2 REAL NOT NULL, caliper3 REAL NOT NULL, calories REAL NOT NULL, comment TEXT,"
+ " FOREIGN KEY(userId) REFERENCES scaleUsers(id)"
+ " ON UPDATE NO ACTION ON DELETE CASCADE)");
// Create new index on datetime + userId
database.execSQL("CREATE UNIQUE INDEX index_scaleMeasurements_userId_datetime"
+ " ON scaleMeasurements (userId, datetime)");
// Copy data from the old table
database.execSQL("INSERT INTO scaleMeasurements"
+ " SELECT id, userId, enabled, datetime, weight, fat, water, muscle,"
+ " visceralFat, lbm, waist, hip, bone, chest,"
+ " thigh, biceps, neck, caliper1,"
+ " caliper2, caliper3, 0 as calories, comment FROM scaleMeasurementsOld");
// Delete old table
database.execSQL("DROP TABLE scaleMeasurementsOld");
database.setTransactionSuccessful();
}
finally {
database.endTransaction();
}
}
};
}

View File

@@ -16,17 +16,16 @@
package com.health.openscale.core.datatypes;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Index;
import androidx.room.PrimaryKey;
import com.j256.simplecsv.common.CsvColumn;
import java.lang.reflect.Field;
import java.util.Date;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Index;
import androidx.room.PrimaryKey;
import timber.log.Timber;
@Entity(tableName = "scaleMeasurements",
@@ -97,6 +96,9 @@ public class ScaleMeasurement implements Cloneable {
@ColumnInfo(name = "caliper3")
private float caliper3;
@CsvColumn(mustBeSupplied = false)
@ColumnInfo(name = "calories")
private float calories;
@CsvColumn(mustBeSupplied = false)
@ColumnInfo(name = "comment")
private String comment;
@@ -346,6 +348,10 @@ public class ScaleMeasurement implements Cloneable {
this.caliper3 = caliper3;
}
public float getCalories() { return calories; }
public void setCalories(float calories) { this.calories = calories; }
public String getComment() {
return comment;
}
@@ -365,6 +371,18 @@ public class ScaleMeasurement implements Cloneable {
public float getBMR(ScaleUser scaleUser) {
float bmr;
// BMR Harris-Benedict equation
if (scaleUser.getGender().isMale()) {
bmr = 66.4730f + (13.7516f * weight) + (5.0033f * scaleUser.getBodyHeight()) - (6.7550f * scaleUser.getAge(dateTime));
} else {
bmr = 655.0955f + (9.5634f * weight) + (1.8496f * scaleUser.getBodyHeight()) - (4.6756f * scaleUser.getAge(dateTime));
}
return bmr; // kCal / day
}
public float getTDEE(ScaleUser scaleUser) {
float factor = 1.0f;
switch (scaleUser.getActivityLevel()) {
@@ -372,27 +390,20 @@ public class ScaleMeasurement implements Cloneable {
factor = 1.2f;
break;
case MILD:
factor = 1.3f;
factor = 1.375f;
break;
case MODERATE:
factor = 1.5f;
factor = 1.55f;
break;
case HEAVY:
factor = 1.7f;
factor = 1.725f;
break;
case EXTREME:
factor = 1.9f;
break;
}
// BMR formula by Mifflin, St Jeor et al: A new predictive equation for resting energy expenditure in healthy individuals
if (scaleUser.getGender().isMale()) {
bmr = 10.0f * weight + 6.25f * scaleUser.getBodyHeight() - 5.0f * scaleUser.getAge(dateTime) + 5.0f;
} else {
bmr = 10.0f * weight + 6.25f * scaleUser.getBodyHeight() - 5.0f * scaleUser.getAge(dateTime) - 161.0f;
}
return bmr * factor; // kCal / day
return factor * getBMR(scaleUser);
}
public float getWHtR(float body_height) {

View File

@@ -0,0 +1,73 @@
/* Copyright (C) 2019 olie.xdev <olie.xdev@googlemail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.health.openscale.gui.views;
import android.content.Context;
import android.graphics.Color;
import com.health.openscale.R;
import com.health.openscale.core.datatypes.ScaleMeasurement;
import com.health.openscale.core.evaluation.EvaluationResult;
import com.health.openscale.core.evaluation.EvaluationSheet;
public class CaloriesMeasurementView extends FloatMeasurementView {
// Don't change key value, it may be stored persistent in preferences
public static final String KEY = "calories";
public CaloriesMeasurementView(Context context) {
super(context, R.string.label_calories, R.drawable.ic_calories);
}
@Override
public String getKey() {
return KEY;
}
@Override
protected float getMeasurementValue(ScaleMeasurement measurement) {
return measurement.getCalories();
}
@Override
protected void setMeasurementValue(float value, ScaleMeasurement measurement) {
measurement.setCalories(value);
}
@Override
public String getUnit() {
return "kCal";
}
@Override
protected float getMaxValue() {
return 100000;
}
@Override
protected int getDecimalPlaces() {
return 0;
}
@Override
public int getColor() {
return Color.parseColor("#e533ff");
}
@Override
protected EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) {
return null;
}
}

View File

@@ -25,7 +25,6 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import androidx.core.content.ContextCompat;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.TypedValue;
@@ -50,6 +49,7 @@ import com.health.openscale.core.evaluation.EvaluationResult;
import java.util.ArrayList;
import java.util.List;
import androidx.core.content.ContextCompat;
import lecho.lib.hellocharts.util.ChartUtils;
import static com.health.openscale.gui.views.MeasurementView.MeasurementViewMode.ADD;
@@ -126,6 +126,8 @@ public abstract class MeasurementView extends TableLayout {
unsorted.add(new Caliper2MeasurementView(context));
unsorted.add(new Caliper3MeasurementView(context));
unsorted.add(new BMRMeasurementView(context));
unsorted.add(new TDEEMeasurementView(context));
unsorted.add(new CaloriesMeasurementView(context));
unsorted.add(new CommentMeasurementView(context));
// Get sort order

View File

@@ -64,6 +64,7 @@ public class MeasurementViewSettings {
case Caliper1MeasurementView.KEY:
case Caliper2MeasurementView.KEY:
case Caliper3MeasurementView.KEY:
case CaloriesMeasurementView.KEY:
defaultValue = false;
break;
default:

View File

@@ -0,0 +1,78 @@
/* Copyright (C) 2019 olie.xdev <olie.xdev@googlemail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.health.openscale.gui.views;
import android.content.Context;
import android.graphics.Color;
import com.health.openscale.R;
import com.health.openscale.core.datatypes.ScaleMeasurement;
import com.health.openscale.core.evaluation.EvaluationResult;
import com.health.openscale.core.evaluation.EvaluationSheet;
public class TDEEMeasurementView extends FloatMeasurementView {
// Don't change key value, it may be stored persistent in preferences
public static final String KEY = "tdee";
public TDEEMeasurementView(Context context) {
super(context, R.string.label_tdee, R.drawable.ic_tdee);
}
@Override
public String getKey() {
return KEY;
}
@Override
public boolean isEditable() {
return false;
}
@Override
protected float getMeasurementValue(ScaleMeasurement measurement) {
return measurement.getTDEE(getScaleUser());
}
@Override
protected void setMeasurementValue(float value, ScaleMeasurement measurement) {
// Empty
}
@Override
public String getUnit() {
return "kCal";
}
@Override
protected float getMaxValue() {
return 10000;
}
@Override
protected int getDecimalPlaces() {
return 0;
}
@Override
public int getColor() {
return Color.parseColor("#6ea626");
}
@Override
protected EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) {
return null;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -226,5 +226,7 @@
<string name="trisa_scale_pairing_succeeded">Die Kopplung ist erfolgreich!
\n
\nWieder verbinden, um Messdaten abzurufen.</string>
<string name="label_tdee">Gesamtenergieumsatz (TDEE)</string>
<string name="label_calories">Kalorien</string>
</resources>
</resources>

View File

@@ -28,6 +28,7 @@
<string name="label_weight">Weight</string>
<string name="label_bmi">Body mass index (BMI)</string>
<string name="label_bmr">Basal metabolic rate (BMR)</string>
<string name="label_tdee">Total Daily Energy Expenditure (TDEE)</string>
<string name="label_fat">Body fat</string>
<string name="label_water">Body water</string>
<string name="label_muscle">Muscle</string>
@@ -230,6 +231,7 @@
<string name="label_thigh">Thigh circumference</string>
<string name="label_biceps">Biceps circumference</string>
<string name="label_neck">Neck circumference</string>
<string name="label_calories">Calories</string>
<string name="label_fat_caliper">Body fat caliper</string>
<string name="label_caliper1_male">Chest skinfold</string>
<string name="label_caliper2_male">Abdominal skinfold</string>