mirror of
https://github.com/dzeiocom/OpenHealth.git
synced 2025-06-07 07:19:54 +00:00
misc: Cleanup Database
This commit is contained in:
parent
9e463d7fd3
commit
a9da9198be
@ -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 ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
|
@ -10,9 +10,8 @@ class FoodRepository @Inject constructor(
|
||||
private val dao: FoodDao,
|
||||
private val offSource: OpenFoodFactService
|
||||
) {
|
||||
suspend fun findOnlineFood(name: String): Response<OFFResult> {
|
||||
return offSource.searchProducts(name)
|
||||
}
|
||||
suspend fun searchOpenFoodFact(name: String): Response<OFFResult> =
|
||||
offSource.searchProducts(name)
|
||||
|
||||
fun getAll() = dao.getAll()
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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?
|
||||
)
|
||||
|
@ -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<OFFProduct>
|
||||
)
|
||||
|
@ -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<OFFResult>
|
||||
|
||||
@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<OFFResult>
|
||||
|
||||
|
@ -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"
|
||||
) {
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user