diff --git a/app/src/main/java/com/dzeio/openhealth/data/AppDatabase.kt b/app/src/main/java/com/dzeio/openhealth/data/AppDatabase.kt index 055fba6..de7efe7 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/AppDatabase.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/AppDatabase.kt @@ -5,8 +5,6 @@ import androidx.room.AutoMigration import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase -import androidx.room.migration.Migration -import androidx.sqlite.db.SupportSQLiteDatabase import com.dzeio.openhealth.data.food.Food import com.dzeio.openhealth.data.food.FoodDao import com.dzeio.openhealth.data.step.Step @@ -16,6 +14,11 @@ import com.dzeio.openhealth.data.water.WaterDao import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.WeightDao +/** + * ROOM SQLite database for the application + * + * It may be replaced if I want to fully encrypt the database + */ @Database( entities = [ Weight::class, @@ -23,16 +26,16 @@ import com.dzeio.openhealth.data.weight.WeightDao Step::class, Food::class ], + // TODO: go back to version 1 when the app is published version = 3, exportSchema = true, autoMigrations = [ - AutoMigration(from = 1, to = 2) + AutoMigration(from = 1, to = 2), + AutoMigration(from = 2, to = 3) ] ) abstract class AppDatabase : RoomDatabase() { -// private val PREPOPULATE_DATA = listOf(Thing("1", "val"), Thing("2", "val 2")) - abstract fun weightDao(): WeightDao abstract fun waterDao(): WaterDao abstract fun stepDao(): StepDao @@ -40,42 +43,29 @@ abstract class AppDatabase : RoomDatabase() { abstract fun foodDao(): FoodDao companion object { + /** + * database name duh + */ private const val DATABASE_NAME = "open_health" // For Singleton instantiation @Volatile private var instance: AppDatabase? = null + // get the Database instance fun getInstance(context: Context): AppDatabase { return instance ?: synchronized(this) { instance ?: buildDatabase(context).also { instance = it } } } - // Create and pre-populate the database. See this article for more details: - // https://medium.com/google-developers/7-pro-tips-for-room-fbadea4bfbd1#4785 + /** + * build teh database + */ private fun buildDatabase(context: Context): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME) - .addMigrations(MIGRATION_2_3) -// .addCallback(object : Callback() { -// override fun onCreate(db: SupportSQLiteDatabase) { -// super.onCreate(db) -// // moving to a new thread -// Executors.newSingleThreadExecutor().execute { -// getInstance(context).thingDao() -// .insert(PREPOPULATE_DATA) -// } -// } -// }) +// .addMigrations(MIGRATION_2_3) .build() } - - private val MIGRATION_2_3 = object : Migration(2, 3) { - override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("ALTER TABLE Food ADD COLUMN serving TEXT NOT NULL") - database.execSQL("ALTER TABLE Food ADD COLUMN image TEXT") - database.execSQL("ALTER TABLE Food ") - } - } } } diff --git a/app/src/main/java/com/dzeio/openhealth/data/converters/.gitkeep b/app/src/main/java/com/dzeio/openhealth/data/converters/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/dzeio/openhealth/data/converters/OffsetDateTimeConverter.kt b/app/src/main/java/com/dzeio/openhealth/data/converters/OffsetDateTimeConverter.kt deleted file mode 100644 index ca107c2..0000000 --- a/app/src/main/java/com/dzeio/openhealth/data/converters/OffsetDateTimeConverter.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.dzeio.openhealth.data.converters - -import androidx.room.TypeConverter -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter - -object TiviTypeConverters { - private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME - - @TypeConverter - @JvmStatic - fun toOffsetDateTime(value: String?): OffsetDateTime? { - return value?.let { - return formatter.parse(value, OffsetDateTime::from) - } - } - - @TypeConverter - @JvmStatic - fun fromOffsetDateTime(date: OffsetDateTime?): String? { - return date?.format(formatter) - } -} diff --git a/app/src/main/java/com/dzeio/openhealth/data/food/Food.kt b/app/src/main/java/com/dzeio/openhealth/data/food/Food.kt index bfda863..3c6c063 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/food/Food.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/food/Food.kt @@ -10,23 +10,62 @@ import java.util.TimeZone data class Food( @PrimaryKey(autoGenerate = true) var id: Long = 0, + + /** + * The product name + */ var name: String, + + /** + * The product serving text + * + * ex: `250ml`, `520g`, etc + */ var serving: String, + + /** + * the quantity taken by the user + */ var quantity: Float, + + /** + * the quantity of proteins there is for 100 quantity + */ var proteins: Float, + + /** + * the quantity of carbohydrates there is for 100 quantity + */ var carbohydrates: Float, + + /** + * the quantity of fat there is for 100 quantity + */ var fat: Float, + + /** + * the quantity of energy there is for 100 quantity + */ var energy: Float, /** - * the url of the image + * the url of the image of the product */ var image: String?, + /** + * When the entry was added to our Database + */ var timestamp: Long = Calendar.getInstance(TimeZone.getTimeZone("UTC")).timeInMillis, ) { companion object { + + /** + * Transform an OpenFoodFact product to use for our Database + */ fun fromOpenFoodFact(food: OFFProduct, quantity: Float? = null): Food { + + // try to know how much was eaten by the user if not said var eaten = quantity ?: food.servingQuantity ?: food.productQuantity ?: 0f if (eaten == 0f) { if (food.servingQuantity != null && food.servingQuantity != 0f) { @@ -37,11 +76,13 @@ data class Food( } return Food( name = food.name, + // do some slight edit on the serving to remove strange entries like `100 g` serving = (food.servingSize ?: food.quantity ?: "unknown").replace(Regex(" +"), ""), quantity = eaten, proteins = food.nutriments.proteins, carbohydrates = food.nutriments.carbohydrates, fat = food.nutriments.fat, + // handle case where the energy is not given in kcal but only in kj energy = food.nutriments.energy ?: (food.nutriments.energyKJ * 0.2390057361).toFloat(), image = food.image ) diff --git a/app/src/main/java/com/dzeio/openhealth/data/food/FoodRepository.kt b/app/src/main/java/com/dzeio/openhealth/data/food/FoodRepository.kt index c00ca7c..767b214 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/food/FoodRepository.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/food/FoodRepository.kt @@ -10,9 +10,8 @@ class FoodRepository @Inject constructor( private val dao: FoodDao, private val offSource: OpenFoodFactService ) { - suspend fun findOnlineFood(name: String): Response { - return offSource.searchProducts(name) - } + suspend fun searchOpenFoodFact(name: String): Response = + offSource.searchProducts(name) fun getAll() = dao.getAll() diff --git a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFNutriments.kt b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFNutriments.kt index a561356..9538c36 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFNutriments.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFNutriments.kt @@ -3,14 +3,33 @@ package com.dzeio.openhealth.data.openfoodfact import com.google.gson.annotations.SerializedName data class OFFNutriments( + /** + * the quantity of carbohydrates in a 100g serving + */ @SerializedName("carbohydrates_100g") var carbohydrates: Float, + + /** + * the energy in kcal in a 100g serving + */ @SerializedName("energy-kcal_100g") var energy: Float?, + + /** + * the energy KL in a 100g serving + */ @SerializedName("energy-kj_100g") var energyKJ: Float, + + /** + * the quantity of fat in a 100g serving + */ @SerializedName("fat_100g") var fat: Float, + + /** + * the quantity of proteins in a 100g serving + */ @SerializedName("proteins_100g") var proteins: Float ) diff --git a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFProduct.kt b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFProduct.kt index 2bc9660..1c44dfc 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFProduct.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFProduct.kt @@ -3,26 +3,51 @@ package com.dzeio.openhealth.data.openfoodfact import com.google.gson.annotations.SerializedName data class OFFProduct( + /** + * the OFF product id + */ @SerializedName("_id") var id: String, + + /** + * the product name + */ @SerializedName("product_name") var name: String, + /** + * the size of a serving + */ @SerializedName("serving_size") var servingSize: String?, + /** + * the size of a serving without the `g`, `ml`, etc + */ @SerializedName("serving_quantity") var servingQuantity: Float?, + /** + * the size of a serving + */ @SerializedName("quantity") var quantity: String?, + /** + * the size of a serving without the `g`, `ml`, etc + */ @SerializedName("product_quantity") var productQuantity: Float?, + /** + * the product nutriments + */ @SerializedName("nutriments") var nutriments: OFFNutriments, + /** + * the product image + */ @SerializedName("image_url") var image: String? ) diff --git a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFResult.kt b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFResult.kt index a872066..3ceb26d 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFResult.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OFFResult.kt @@ -3,6 +3,9 @@ package com.dzeio.openhealth.data.openfoodfact import com.google.gson.annotations.SerializedName data class OFFResult( + /** + * the list of products + */ @SerializedName("products") var products: List ) diff --git a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OpenFoodFactService.kt b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OpenFoodFactService.kt index 84b7b32..e3a3d19 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OpenFoodFactService.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/openfoodfact/OpenFoodFactService.kt @@ -1,5 +1,6 @@ package com.dzeio.openhealth.data.openfoodfact +import com.dzeio.openhealth.BuildConfig import com.google.gson.GsonBuilder import retrofit2.Response import retrofit2.Retrofit @@ -30,11 +31,17 @@ interface OpenFoodFactService { } } - @Headers("User-Agent: OpenHealth - Android - Version 1.0 - https://github.com/dzeiocom/OpenHealth") + /** + * Search a product by it's name + */ + @Headers("User-Agent: OpenHealth - Android - Version ${BuildConfig.VERSION_NAME} - https://github.com/dzeiocom/OpenHealth") @GET("/cgi/search.pl?json=true&fields=_id,nutriments,product_name,serving_quantity,serving_size,quantity,product_quantity,image_url&action=process") suspend fun searchProducts(@Query("search_terms2") name: String): Response - @Headers("User-Agent: OpenHealth - Android - Version 1.0 - https://github.com/dzeiocom/OpenHealth") + /** + * Search a product by it's barcode + */ + @Headers("User-Agent: OpenHealth - Android - Version ${BuildConfig.VERSION_NAME} - https://github.com/dzeiocom/OpenHealth") @GET("/api/v2/search?fields=_id,nutriments,product_name,serving_quantity") suspend fun findByCode(@Query("code") code: String): Response diff --git a/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt b/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt index 1c4f78c..835287c 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt @@ -12,6 +12,10 @@ import java.util.TimeZone @Entity() data class Step( @PrimaryKey(autoGenerate = true) var id: Long = 0, + + /** + * the raw number of step + */ var value: Int = 0, /** * Timestamp down to an hour @@ -20,6 +24,12 @@ data class Step( */ @ColumnInfo(index = true) var timestamp: Long = 0, + + /** + * the source for the Entry + * + * note: Unused currently but kept for future usage + */ var source: String = "OpenHealth" ) { diff --git a/app/src/main/java/com/dzeio/openhealth/data/step/StepSource.kt b/app/src/main/java/com/dzeio/openhealth/data/step/StepSource.kt index 5812741..b9e72de 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/step/StepSource.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/step/StepSource.kt @@ -12,10 +12,15 @@ import com.dzeio.openhealth.Application import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.runBlocking +/** + * Class that allows us to get Sensor datas for the internal step counter + * + * TODO: rewrite to use the new libs + */ class StepSource( private val context: Context, private val callback: ((Float) -> Unit)? = null -): SensorEventListener { +) : SensorEventListener { companion object { const val TAG = "${Application.TAG}/StepSource" diff --git a/app/src/main/java/com/dzeio/openhealth/data/water/Water.kt b/app/src/main/java/com/dzeio/openhealth/data/water/Water.kt index 2cbf4ae..02d6f57 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/water/Water.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/water/Water.kt @@ -11,9 +11,23 @@ import java.util.TimeZone @Entity() data class Water( @PrimaryKey(autoGenerate = true) var id: Long = 0, + + /** + * the quantity of water in ML drank by the user + */ var value: Int = 0, + + /** + * when the water was drank precise to the day + */ @ColumnInfo(index = true) var timestamp: Long = 0, + + /** + * the source for the Entry + * + * note: Unused currently but kept for future usage + */ var source: String = "OpenHealth" ) { init { diff --git a/app/src/main/java/com/dzeio/openhealth/data/weight/Weight.kt b/app/src/main/java/com/dzeio/openhealth/data/weight/Weight.kt index ed4c280..980154a 100644 --- a/app/src/main/java/com/dzeio/openhealth/data/weight/Weight.kt +++ b/app/src/main/java/com/dzeio/openhealth/data/weight/Weight.kt @@ -14,9 +14,19 @@ data class Weight( * Store the weight in kilograms */ var weight: Float = 0f, + + /** + * when the weight was taken precise to the millisecond + */ @ColumnInfo(index = true) var timestamp: Long = System.currentTimeMillis(), - var source: String = "" + + /** + * the source for the Entry + * + * note: Unused currently but kept for future usage + */ + var source: String = "OpenHealth" ) { fun formatTimestamp(): String = getDateInstance().format(Date(timestamp)); }