mirror of
https://github.com/dzeiocom/OpenHealth.git
synced 2025-04-22 19:02:16 +00:00
feat: Too much things to say.
This commit is contained in:
parent
357024770a
commit
2628bc1403
@ -50,7 +50,6 @@ android {
|
|||||||
storeFile = file(keystoreProperties["storeFile"] as String)
|
storeFile = file(keystoreProperties["storeFile"] as String)
|
||||||
}
|
}
|
||||||
} catch (_: Exception) {}
|
} catch (_: Exception) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,14 +89,22 @@ android {
|
|||||||
|
|
||||||
getByName("release") {
|
getByName("release") {
|
||||||
// Slimmer version
|
// Slimmer version
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = false
|
||||||
|
isShrinkResources = false
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
signingConfig = signingConfigs.getByName("release")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
|
|
||||||
getByName("debug") {
|
getByName("debug") {
|
||||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
applicationIdSuffix = ".dev"
|
applicationIdSuffix = ".dev"
|
||||||
versionNameSuffix = "-dev"
|
versionNameSuffix = "-dev"
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
@ -130,7 +137,7 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Dzeio Charts
|
// Dzeio Charts
|
||||||
implementation("com.dzeio:charts:cbd5f57f8d")
|
implementation("com.dzeio:charts:fe20f90654")
|
||||||
|
|
||||||
// Dzeio Crash Handler
|
// Dzeio Crash Handler
|
||||||
implementation("com.dzeio:crashhandler:1.0.1")
|
implementation("com.dzeio:crashhandler:1.0.1")
|
||||||
|
67
app/proguard-rules.pro
vendored
67
app/proguard-rules.pro
vendored
@ -18,4 +18,69 @@
|
|||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
|
||||||
|
# EnclosingMethod is required to use InnerClasses.
|
||||||
|
-keepattributes Signature, InnerClasses, EnclosingMethod
|
||||||
|
|
||||||
|
# Retrofit does reflection on method and parameter annotations.
|
||||||
|
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
|
||||||
|
|
||||||
|
# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
|
||||||
|
-keepattributes AnnotationDefault
|
||||||
|
|
||||||
|
# Retain service method parameters when optimizing.
|
||||||
|
-keepclassmembers,allowshrinking,allowobfuscation interface * {
|
||||||
|
@retrofit2.http.* <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ignore annotation used for build tooling.
|
||||||
|
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||||
|
|
||||||
|
# Ignore JSR 305 annotations for embedding nullability information.
|
||||||
|
-dontwarn javax.annotation.**
|
||||||
|
|
||||||
|
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
|
||||||
|
-dontwarn kotlin.Unit
|
||||||
|
|
||||||
|
# Top-level functions that can only be used by Kotlin.
|
||||||
|
-dontwarn retrofit2.KotlinExtensions
|
||||||
|
-dontwarn retrofit2.KotlinExtensions$*
|
||||||
|
|
||||||
|
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
|
||||||
|
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
|
||||||
|
-if interface * { @retrofit2.http.* <methods>; }
|
||||||
|
-keep,allowobfuscation interface <1>
|
||||||
|
|
||||||
|
# Keep inherited services.
|
||||||
|
-if interface * { @retrofit2.http.* <methods>; }
|
||||||
|
-keep,allowobfuscation interface * extends <1>
|
||||||
|
|
||||||
|
# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).
|
||||||
|
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
|
||||||
|
-keep,allowobfuscation,allowshrinking class retrofit2.Response
|
||||||
|
|
||||||
|
# With R8 full mode generic signatures are stripped for classes that are not
|
||||||
|
# kept. Suspend functions are wrapped in continuations where the type argument
|
||||||
|
# is used.
|
||||||
|
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
|
||||||
|
|
||||||
|
|
||||||
|
# JSR 305 annotations are for embedding nullability information.
|
||||||
|
-dontwarn javax.annotation.**
|
||||||
|
|
||||||
|
# A resource is loaded with a relative path so the package of this class must be preserved.
|
||||||
|
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
|
||||||
|
|
||||||
|
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
|
||||||
|
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||||
|
|
||||||
|
# OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
|
||||||
|
-dontwarn okhttp3.internal.platform.**
|
||||||
|
-dontwarn org.conscrypt.**
|
||||||
|
-dontwarn org.bouncycastle.**
|
||||||
|
-dontwarn org.openjsse.**
|
||||||
|
|
||||||
|
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
|
||||||
|
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "2acd5897bbf15393886259605a1df934",
|
"identityHash": "414712cc283c7f1d14cde8e00da277fb",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "Weight",
|
"tableName": "Weight",
|
||||||
@ -34,10 +34,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
]
|
||||||
"autoGenerate": true
|
|
||||||
},
|
},
|
||||||
"indices": [
|
"indices": [
|
||||||
{
|
{
|
||||||
@ -82,10 +82,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
]
|
||||||
"autoGenerate": true
|
|
||||||
},
|
},
|
||||||
"indices": [
|
"indices": [
|
||||||
{
|
{
|
||||||
@ -130,10 +130,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
]
|
||||||
"autoGenerate": true
|
|
||||||
},
|
},
|
||||||
"indices": [
|
"indices": [
|
||||||
{
|
{
|
||||||
@ -147,12 +147,86 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Food",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `serving` TEXT NOT NULL, `quantity` REAL NOT NULL, `proteins` REAL NOT NULL, `carbohydrates` REAL NOT NULL, `fat` REAL NOT NULL, `energy` REAL NOT NULL, `image` TEXT, `timestamp` INTEGER NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serving",
|
||||||
|
"columnName": "serving",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "quantity",
|
||||||
|
"columnName": "quantity",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "proteins",
|
||||||
|
"columnName": "proteins",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "carbohydrates",
|
||||||
|
"columnName": "carbohydrates",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "fat",
|
||||||
|
"columnName": "fat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "energy",
|
||||||
|
"columnName": "energy",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "image",
|
||||||
|
"columnName": "image",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timestamp",
|
||||||
|
"columnName": "timestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"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, '2acd5897bbf15393886259605a1df934')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '414712cc283c7f1d14cde8e00da277fb')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,226 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 2,
|
|
||||||
"identityHash": "0f92ae44f4503b964d4986959a15ef4e",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "Weight",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `weight` REAL NOT NULL, `timestamp` INTEGER NOT NULL, `source` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "weight",
|
|
||||||
"columnName": "weight",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "source",
|
|
||||||
"columnName": "source",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_Weight_timestamp",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"timestamp"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Weight_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "Water",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `value` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `source` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "value",
|
|
||||||
"columnName": "value",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "source",
|
|
||||||
"columnName": "source",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_Water_timestamp",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"timestamp"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Water_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "Step",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `value` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `source` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "value",
|
|
||||||
"columnName": "value",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "source",
|
|
||||||
"columnName": "source",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_Step_timestamp",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"timestamp"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Step_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "Food",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `serving` TEXT NOT NULL, `quantity` INTEGER NOT NULL, `proteins` REAL NOT NULL, `carbohydrates` REAL NOT NULL, `fat` REAL NOT NULL, `energy` REAL NOT NULL, `timestamp` INTEGER NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "serving",
|
|
||||||
"columnName": "serving",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "proteins",
|
|
||||||
"columnName": "proteins",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "carbohydrates",
|
|
||||||
"columnName": "carbohydrates",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "fat",
|
|
||||||
"columnName": "fat",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "energy",
|
|
||||||
"columnName": "energy",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"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, '0f92ae44f4503b964d4986959a15ef4e')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,232 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 3,
|
|
||||||
"identityHash": "414712cc283c7f1d14cde8e00da277fb",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "Weight",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `weight` REAL NOT NULL, `timestamp` INTEGER NOT NULL, `source` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "weight",
|
|
||||||
"columnName": "weight",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "source",
|
|
||||||
"columnName": "source",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_Weight_timestamp",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"timestamp"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Weight_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "Water",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `value` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `source` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "value",
|
|
||||||
"columnName": "value",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "source",
|
|
||||||
"columnName": "source",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_Water_timestamp",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"timestamp"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Water_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "Step",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `value` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `source` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "value",
|
|
||||||
"columnName": "value",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "source",
|
|
||||||
"columnName": "source",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_Step_timestamp",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"timestamp"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_Step_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "Food",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `serving` TEXT NOT NULL, `quantity` REAL NOT NULL, `proteins` REAL NOT NULL, `carbohydrates` REAL NOT NULL, `fat` REAL NOT NULL, `energy` REAL NOT NULL, `image` TEXT, `timestamp` INTEGER NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "serving",
|
|
||||||
"columnName": "serving",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "proteins",
|
|
||||||
"columnName": "proteins",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "carbohydrates",
|
|
||||||
"columnName": "carbohydrates",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "fat",
|
|
||||||
"columnName": "fat",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "energy",
|
|
||||||
"columnName": "energy",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "image",
|
|
||||||
"columnName": "image",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "timestamp",
|
|
||||||
"columnName": "timestamp",
|
|
||||||
"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, '414712cc283c7f1d14cde8e00da277fb')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,13 +7,9 @@ import com.dzeio.openhealth.core.BaseAdapter
|
|||||||
import com.dzeio.openhealth.core.BaseViewHolder
|
import com.dzeio.openhealth.core.BaseViewHolder
|
||||||
import com.dzeio.openhealth.data.food.Food
|
import com.dzeio.openhealth.data.food.Food
|
||||||
import com.dzeio.openhealth.databinding.ItemFoodBinding
|
import com.dzeio.openhealth.databinding.ItemFoodBinding
|
||||||
import com.dzeio.openhealth.utils.DownloadImageTask
|
import com.dzeio.openhealth.utils.NetworkUtils
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
class FoodAdapter : BaseAdapter<Food, ItemFoodBinding>() {
|
class FoodAdapter : BaseAdapter<Food, ItemFoodBinding>() {
|
||||||
|
|
||||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> ItemFoodBinding
|
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> ItemFoodBinding
|
||||||
@ -26,16 +22,13 @@ class FoodAdapter : BaseAdapter<Food, ItemFoodBinding>() {
|
|||||||
item: Food,
|
item: Food,
|
||||||
position: Int
|
position: Int
|
||||||
) {
|
) {
|
||||||
|
// Download remote picture
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
if (item.image != null) {
|
||||||
|
NetworkUtils.getImageInBackground(holder.binding.productImage, item.image!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download remote picture
|
|
||||||
DownloadImageTask(holder.binding.productImage).execute(item.image)
|
|
||||||
|
|
||||||
// set the food name
|
// set the food name
|
||||||
holder.binding.foodName.text = item.name
|
holder.binding.foodName.text = item.name + " ${item.id}"
|
||||||
|
|
||||||
// set the food description
|
// set the food description
|
||||||
holder.binding.foodDescription.text = holder.itemView.context.getString(
|
holder.binding.foodDescription.text = holder.itemView.context.getString(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.dzeio.openhealth.adapters
|
package com.dzeio.openhealth.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.dzeio.openhealth.R
|
import com.dzeio.openhealth.R
|
||||||
import com.dzeio.openhealth.core.BaseAdapter
|
import com.dzeio.openhealth.core.BaseAdapter
|
||||||
@ -15,6 +16,8 @@ class StepsAdapter() : BaseAdapter<Step, LayoutItemListBinding>() {
|
|||||||
|
|
||||||
var onItemClick: ((weight: Step) -> Unit)? = null
|
var onItemClick: ((weight: Step) -> Unit)? = null
|
||||||
|
|
||||||
|
var isDay = false
|
||||||
|
|
||||||
override fun onBindData(
|
override fun onBindData(
|
||||||
holder: BaseViewHolder<LayoutItemListBinding>,
|
holder: BaseViewHolder<LayoutItemListBinding>,
|
||||||
item: Step,
|
item: Step,
|
||||||
@ -27,7 +30,13 @@ class StepsAdapter() : BaseAdapter<Step, LayoutItemListBinding>() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// set the datetime
|
// set the datetime
|
||||||
holder.binding.datetime.text = item.formatTimestamp()
|
holder.binding.datetime.text = item.formatTimestamp(!isDay)
|
||||||
|
|
||||||
|
if (isDay) {
|
||||||
|
holder.binding.iconRight.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
holder.binding.iconRight.setImageResource(R.drawable.ic_zoom_out_map)
|
||||||
|
}
|
||||||
|
|
||||||
// set the callback
|
// set the callback
|
||||||
holder.binding.edit.setOnClickListener {
|
holder.binding.edit.setOnClickListener {
|
||||||
|
@ -10,7 +10,6 @@ import androidx.viewbinding.ViewBinding
|
|||||||
*/
|
*/
|
||||||
abstract class BaseActivity<VB : ViewBinding>() : AppCompatActivity() {
|
abstract class BaseActivity<VB : ViewBinding>() : AppCompatActivity() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to inflate the Fragment Bindings
|
* Function to inflate the Fragment Bindings
|
||||||
*
|
*
|
||||||
|
@ -47,5 +47,4 @@ abstract class BaseAdapter<T, VB : ViewBinding> : RecyclerView.Adapter<BaseViewH
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,9 @@ import androidx.viewbinding.ViewBinding
|
|||||||
*
|
*
|
||||||
* note: Dialog crash app with viewmodel error? add @AndroidEntryPoint
|
* note: Dialog crash app with viewmodel error? add @AndroidEntryPoint
|
||||||
*/
|
*/
|
||||||
abstract class BaseDialog<VM : BaseViewModel, VB : ViewBinding>(private val viewModelClass: Class<VM>) :
|
abstract class BaseDialog<VM : BaseViewModel, VB : ViewBinding>(
|
||||||
|
private val viewModelClass: Class<VM>
|
||||||
|
) :
|
||||||
BaseSimpleDialog<VB>() {
|
BaseSimpleDialog<VB>() {
|
||||||
|
|
||||||
val viewModel by lazy {
|
val viewModel by lazy {
|
||||||
|
@ -16,7 +16,9 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
/**
|
/**
|
||||||
* Base around the DialogFragment class to simplify usage
|
* Base around the DialogFragment class to simplify usage
|
||||||
*/
|
*/
|
||||||
abstract class BaseFullscreenDialog<VM : BaseViewModel, VB : ViewBinding>(private val viewModelClass: Class<VM>) : DialogFragment() {
|
abstract class BaseFullscreenDialog<VM : BaseViewModel, VB : ViewBinding>(
|
||||||
|
private val viewModelClass: Class<VM>
|
||||||
|
) : DialogFragment() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lazyload the viewModel
|
* Lazyload the viewModel
|
||||||
@ -33,7 +35,6 @@ abstract class BaseFullscreenDialog<VM : BaseViewModel, VB : ViewBinding>(privat
|
|||||||
*/
|
*/
|
||||||
abstract val bindingInflater: (LayoutInflater) -> VB
|
abstract val bindingInflater: (LayoutInflater) -> VB
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function run when the dialog was created
|
* Function run when the dialog was created
|
||||||
*/
|
*/
|
||||||
@ -44,7 +45,6 @@ abstract class BaseFullscreenDialog<VM : BaseViewModel, VB : ViewBinding>(privat
|
|||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
|
|
||||||
_binding = bindingInflater(inflater)
|
_binding = bindingInflater(inflater)
|
||||||
|
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
|
@ -39,7 +39,6 @@ abstract class BaseStaticFragment<VB : ViewBinding> : Fragment() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy binding
|
* Destroy binding
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,5 @@ import androidx.viewbinding.ViewBinding
|
|||||||
* Simple implementation of RecyclerView.ViewHolder to limitate usage
|
* Simple implementation of RecyclerView.ViewHolder to limitate usage
|
||||||
*/
|
*/
|
||||||
class BaseViewHolder<VB : ViewBinding>(
|
class BaseViewHolder<VB : ViewBinding>(
|
||||||
val binding : VB
|
val binding: VB
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
|
||||||
|
@ -10,7 +10,6 @@ open class Observable<T>(baseValue: T) {
|
|||||||
|
|
||||||
private val functionObservers: ArrayList<(T) -> Unit> = ArrayList()
|
private val functionObservers: ArrayList<(T) -> Unit> = ArrayList()
|
||||||
|
|
||||||
|
|
||||||
fun addObserver(fn: (T) -> Unit) {
|
fun addObserver(fn: (T) -> Unit) {
|
||||||
if (!functionObservers.contains(fn)) {
|
if (!functionObservers.contains(fn)) {
|
||||||
functionObservers.add(fn)
|
functionObservers.add(fn)
|
||||||
@ -38,7 +37,6 @@ open class Observable<T>(baseValue: T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun notifyObservers() {
|
fun notifyObservers() {
|
||||||
|
|
||||||
// Notify Functions
|
// Notify Functions
|
||||||
for (fn in functionObservers) {
|
for (fn in functionObservers) {
|
||||||
notifyObserver(fn)
|
notifyObserver(fn)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.dzeio.openhealth.data
|
package com.dzeio.openhealth.data
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.room.AutoMigration
|
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
@ -27,12 +26,8 @@ import com.dzeio.openhealth.data.weight.WeightDao
|
|||||||
Food::class
|
Food::class
|
||||||
],
|
],
|
||||||
// TODO: go back to version 1 when the app is published
|
// TODO: go back to version 1 when the app is published
|
||||||
version = 3,
|
version = 1,
|
||||||
exportSchema = true,
|
exportSchema = true
|
||||||
autoMigrations = [
|
|
||||||
AutoMigration(from = 1, to = 2),
|
|
||||||
AutoMigration(from = 2, to = 3)
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ data class Food(
|
|||||||
/**
|
/**
|
||||||
* When the entry was added to our Database
|
* When the entry was added to our Database
|
||||||
*/
|
*/
|
||||||
var timestamp: Long = Calendar.getInstance(TimeZone.getTimeZone("UTC")).timeInMillis,
|
var timestamp: Long = Calendar.getInstance(TimeZone.getTimeZone("UTC")).timeInMillis
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -66,7 +66,10 @@ data class Food(
|
|||||||
*/
|
*/
|
||||||
fun fromOpenFoodFact(food: OFFProduct, quantity: Float? = null): Food? {
|
fun fromOpenFoodFact(food: OFFProduct, quantity: Float? = null): Food? {
|
||||||
// filter out foods that we can't use in the app
|
// filter out foods that we can't use in the app
|
||||||
if (food.name == null || ((food.servingSize == null || food.servingSize == "") && (food.quantity == null || food.quantity == "") && food.servingQuantity == null && food.productQuantity == null)) {
|
if (
|
||||||
|
food.nutriments == null ||
|
||||||
|
food.name == null ||
|
||||||
|
((food.servingSize == null || food.servingSize == "") && (food.quantity == null || food.quantity == "") && food.servingQuantity == null && food.productQuantity == null)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,10 +81,13 @@ data class Food(
|
|||||||
} else if (food.productQuantity != null && food.productQuantity != 0f) {
|
} else if (food.productQuantity != null && food.productQuantity != 0f) {
|
||||||
eaten = food.productQuantity!!
|
eaten = food.productQuantity!!
|
||||||
} else if (food.servingSize != null || food.quantity != null) {
|
} else if (food.servingSize != null || food.quantity != null) {
|
||||||
Log.d("pouet", ".${food.servingSize ?: food.quantity}. .${(food.servingSize ?: food.quantity)!!.replace(Regex(" +\\w+$"), "")}. ${food}")
|
eaten = (food.servingSize ?: food.quantity)!!.trim().replace(
|
||||||
eaten = (food.servingSize ?: food.quantity)!!.trim().replace(Regex(" +\\w+$"), "").toInt().toFloat()
|
Regex(" +\\w+$"),
|
||||||
|
""
|
||||||
|
).toInt().toFloat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.d("Food", "$food")
|
||||||
return Food(
|
return Food(
|
||||||
name = food.name!!,
|
name = food.name!!,
|
||||||
// do some slight edit on the serving to remove strange entries like `100 g`
|
// do some slight edit on the serving to remove strange entries like `100 g`
|
||||||
@ -91,7 +97,8 @@ data class Food(
|
|||||||
carbohydrates = food.nutriments.carbohydrates,
|
carbohydrates = food.nutriments.carbohydrates,
|
||||||
fat = food.nutriments.fat,
|
fat = food.nutriments.fat,
|
||||||
// handle case where the energy is not given in kcal but only in kj
|
// handle case where the energy is not given in kcal but only in kj
|
||||||
energy = food.nutriments.energy ?: (food.nutriments.energyKJ * 0.2390057361).toFloat(),
|
energy = food.nutriments.energy
|
||||||
|
?: (food.nutriments.energyKJ * 0.2390057361).toFloat(),
|
||||||
image = food.image
|
image = food.image
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,76 @@
|
|||||||
package com.dzeio.openhealth.data.food
|
package com.dzeio.openhealth.data.food
|
||||||
|
|
||||||
import com.dzeio.openhealth.data.openfoodfact.OFFResult
|
|
||||||
import com.dzeio.openhealth.data.openfoodfact.OpenFoodFactService
|
import com.dzeio.openhealth.data.openfoodfact.OpenFoodFactService
|
||||||
import retrofit2.Response
|
import com.dzeio.openhealth.utils.NetworkResult
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.IOException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class FoodRepository @Inject constructor(
|
class FoodRepository @Inject constructor(
|
||||||
private val dao: FoodDao,
|
private val dao: FoodDao,
|
||||||
private val offSource: OpenFoodFactService
|
private val offSource: OpenFoodFactService
|
||||||
) {
|
) {
|
||||||
suspend fun searchOpenFoodFact(name: String): Response<OFFResult> =
|
|
||||||
offSource.searchProducts(name)
|
suspend fun searchFood(name: String): Flow<NetworkResult<List<Food>>> = channelFlow {
|
||||||
|
val result = NetworkResult<List<Food>>()
|
||||||
|
val items = arrayListOf<Food>()
|
||||||
|
var otherFinished = false
|
||||||
|
|
||||||
|
launch { // Search OFF
|
||||||
|
try {
|
||||||
|
val request = offSource.searchProducts(name)
|
||||||
|
if (!request.isSuccessful) {
|
||||||
|
if (otherFinished) {
|
||||||
|
result.status = NetworkResult.NetworkStatus.ERRORED
|
||||||
|
} else {
|
||||||
|
otherFinished = true
|
||||||
|
}
|
||||||
|
send(result)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
val offProducts =
|
||||||
|
offSource.searchProducts(name)
|
||||||
|
.body()?.products?.map { Food.fromOpenFoodFact(it) }
|
||||||
|
|
||||||
|
if (offProducts != null) {
|
||||||
|
items.addAll(offProducts.filterNotNull())
|
||||||
|
result.data = items
|
||||||
|
if (otherFinished) {
|
||||||
|
result.status = NetworkResult.NetworkStatus.FINISHED
|
||||||
|
} else {
|
||||||
|
otherFinished = true
|
||||||
|
}
|
||||||
|
send(result)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
if (otherFinished) {
|
||||||
|
result.status = NetworkResult.NetworkStatus.ERRORED
|
||||||
|
} else {
|
||||||
|
otherFinished = true
|
||||||
|
}
|
||||||
|
send(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch { // search local DB
|
||||||
|
getAll().collectLatest { list ->
|
||||||
|
val filtered = list.filter { it.name.contains(name, true) }
|
||||||
|
items.removeAll { it.id > 0 }
|
||||||
|
items.addAll(0, filtered)
|
||||||
|
|
||||||
|
result.data = items
|
||||||
|
if (otherFinished) {
|
||||||
|
result.status = NetworkResult.NetworkStatus.FINISHED
|
||||||
|
} else {
|
||||||
|
otherFinished = true
|
||||||
|
}
|
||||||
|
send(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getAll() = dao.getAll()
|
fun getAll() = dao.getAll()
|
||||||
|
|
||||||
@ -22,5 +81,4 @@ class FoodRepository @Inject constructor(
|
|||||||
suspend fun delete(food: Food) = dao.delete(food)
|
suspend fun delete(food: Food) = dao.delete(food)
|
||||||
|
|
||||||
suspend fun update(food: Food) = dao.update(food)
|
suspend fun update(food: Food) = dao.update(food)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,19 +44,24 @@ data class Step(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatTimestamp(): String {
|
fun formatTimestamp(removeTime: Boolean = false): String {
|
||||||
val formatter = DateFormat.getDateTimeInstance(
|
val formatter = if (removeTime) {
|
||||||
DateFormat.SHORT,
|
DateFormat.getDateInstance(
|
||||||
DateFormat.SHORT,
|
DateFormat.SHORT,
|
||||||
Locale.getDefault()
|
Locale.getDefault()
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
DateFormat.getDateTimeInstance(
|
||||||
|
DateFormat.SHORT,
|
||||||
|
DateFormat.SHORT,
|
||||||
|
Locale.getDefault()
|
||||||
|
)
|
||||||
|
}
|
||||||
return formatter.format(Date(this.timestamp))
|
return formatter.format(Date(this.timestamp))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isToday(): Boolean {
|
fun isToday(): Boolean {
|
||||||
val it = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
val it = getDay()
|
||||||
it.timeInMillis = timestamp
|
|
||||||
it.set(Calendar.HOUR, 0)
|
|
||||||
|
|
||||||
val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
||||||
|
|
||||||
@ -64,7 +69,17 @@ data class Step(
|
|||||||
cal.set(Calendar.MINUTE, 0)
|
cal.set(Calendar.MINUTE, 0)
|
||||||
cal.set(Calendar.SECOND, 0)
|
cal.set(Calendar.SECOND, 0)
|
||||||
cal.set(Calendar.MILLISECOND, 0)
|
cal.set(Calendar.MILLISECOND, 0)
|
||||||
return it.timeInMillis == cal.timeInMillis
|
return it == cal.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDay(): Long {
|
||||||
|
val it = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply {
|
||||||
|
timeInMillis = timestamp
|
||||||
|
set(Calendar.HOUR, 0)
|
||||||
|
|
||||||
|
set(Calendar.AM_PM, Calendar.AM)
|
||||||
|
}
|
||||||
|
return it.timeInMillis
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCurrent(): Boolean {
|
fun isCurrent(): Boolean {
|
||||||
|
@ -7,7 +7,7 @@ import androidx.navigation.fragment.navArgs
|
|||||||
import com.dzeio.openhealth.R
|
import com.dzeio.openhealth.R
|
||||||
import com.dzeio.openhealth.core.BaseDialog
|
import com.dzeio.openhealth.core.BaseDialog
|
||||||
import com.dzeio.openhealth.databinding.DialogFoodProductBinding
|
import com.dzeio.openhealth.databinding.DialogFoodProductBinding
|
||||||
import com.dzeio.openhealth.utils.DownloadImageTask
|
import com.dzeio.openhealth.utils.NetworkUtils
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@ -61,7 +61,12 @@ class FoodDialog :
|
|||||||
updateGraphs(null)
|
updateGraphs(null)
|
||||||
|
|
||||||
binding.serving.text = "Serving: ${it.serving}"
|
binding.serving.text = "Serving: ${it.serving}"
|
||||||
DownloadImageTask(binding.image).execute(it.image)
|
if (it.image != null) {
|
||||||
|
NetworkUtils.getImageInBackground(
|
||||||
|
binding.image,
|
||||||
|
it.image!!
|
||||||
|
)
|
||||||
|
}
|
||||||
binding.quantity.setText(it.quantity.toString())
|
binding.quantity.setText(it.quantity.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,16 @@ import com.dzeio.openhealth.R
|
|||||||
import com.dzeio.openhealth.adapters.FoodAdapter
|
import com.dzeio.openhealth.adapters.FoodAdapter
|
||||||
import com.dzeio.openhealth.core.BaseDialog
|
import com.dzeio.openhealth.core.BaseDialog
|
||||||
import com.dzeio.openhealth.databinding.DialogFoodSearchProductBinding
|
import com.dzeio.openhealth.databinding.DialogFoodSearchProductBinding
|
||||||
|
import com.dzeio.openhealth.utils.NetworkResult
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SearchFoodDialog :
|
class SearchFoodDialog :
|
||||||
BaseDialog<SearchFoodDialogViewModel, DialogFoodSearchProductBinding>(SearchFoodDialogViewModel::class.java) {
|
BaseDialog<SearchFoodDialogViewModel, DialogFoodSearchProductBinding>(
|
||||||
|
SearchFoodDialogViewModel::class.java
|
||||||
|
) {
|
||||||
|
|
||||||
override val bindingInflater: (LayoutInflater) -> DialogFoodSearchProductBinding =
|
override val bindingInflater: (LayoutInflater) -> DialogFoodSearchProductBinding =
|
||||||
DialogFoodSearchProductBinding::inflate
|
DialogFoodSearchProductBinding::inflate
|
||||||
@ -42,7 +45,6 @@ class SearchFoodDialog :
|
|||||||
btn.setOnClickListener {
|
btn.setOnClickListener {
|
||||||
viewModel.search(binding.input.text.toString())
|
viewModel.search(binding.input.text.toString())
|
||||||
binding.loading.visibility = View.VISIBLE
|
binding.loading.visibility = View.VISIBLE
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,8 +52,6 @@ class SearchFoodDialog :
|
|||||||
override fun onCreated() {
|
override fun onCreated() {
|
||||||
super.onCreated()
|
super.onCreated()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val recycler = binding.list
|
val recycler = binding.list
|
||||||
|
|
||||||
val manager = LinearLayoutManager(requireContext())
|
val manager = LinearLayoutManager(requireContext())
|
||||||
@ -59,7 +59,6 @@ class SearchFoodDialog :
|
|||||||
|
|
||||||
val adapter = FoodAdapter()
|
val adapter = FoodAdapter()
|
||||||
adapter.onItemClick = {
|
adapter.onItemClick = {
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val id = viewModel.addProduct(it)
|
val id = viewModel.addProduct(it)
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
@ -73,9 +72,13 @@ class SearchFoodDialog :
|
|||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
|
|
||||||
viewModel.items.observe(this) {
|
viewModel.items.observe(this) {
|
||||||
adapter.set(it)
|
adapter.set(it.data ?: arrayListOf())
|
||||||
binding.loading.visibility = View.GONE
|
if (it.status == NetworkResult.NetworkStatus.FINISHED) {
|
||||||
|
binding.loading.visibility = View.GONE
|
||||||
|
} else if (it.status == NetworkResult.NetworkStatus.ERRORED) {
|
||||||
|
binding.errorText.visibility = View.VISIBLE
|
||||||
|
binding.loading.visibility = View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,35 +5,30 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.dzeio.openhealth.core.BaseViewModel
|
import com.dzeio.openhealth.core.BaseViewModel
|
||||||
import com.dzeio.openhealth.data.food.Food
|
import com.dzeio.openhealth.data.food.Food
|
||||||
import com.dzeio.openhealth.data.food.FoodRepository
|
import com.dzeio.openhealth.data.food.FoodRepository
|
||||||
import com.dzeio.openhealth.data.openfoodfact.OpenFoodFactService
|
import com.dzeio.openhealth.utils.NetworkResult
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.ArrayList
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SearchFoodDialogViewModel @Inject internal constructor(
|
class SearchFoodDialogViewModel @Inject internal constructor(
|
||||||
private val foodRepository: FoodRepository,
|
private val foodRepository: FoodRepository
|
||||||
private val foodFactService: OpenFoodFactService
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
val items: MutableLiveData<List<Food>> = MutableLiveData()
|
val items: MutableLiveData<NetworkResult<List<Food>>> = MutableLiveData()
|
||||||
|
|
||||||
fun search(text: String) {
|
fun search(text: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = foodFactService.searchProducts(text)
|
foodRepository.searchFood(text).collectLatest {
|
||||||
val product = response.body()
|
items.postValue(it)
|
||||||
if (product != null) {
|
|
||||||
|
|
||||||
items.postValue(
|
|
||||||
product.products
|
|
||||||
.map { Food.fromOpenFoodFact(it) }
|
|
||||||
.filter { it != null } as List<Food>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addProduct(product: Food): Long {
|
suspend fun addProduct(product: Food): Long {
|
||||||
|
if (product.id > 0) {
|
||||||
|
product.id = 0
|
||||||
|
}
|
||||||
return foodRepository.add(product)
|
return foodRepository.add(product)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,14 @@ import android.animation.ValueAnimator
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Paint
|
||||||
import android.graphics.RectF
|
import android.graphics.RectF
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.dzeio.charts.Entry
|
import com.dzeio.charts.Entry
|
||||||
|
import com.dzeio.charts.axis.Line
|
||||||
import com.dzeio.charts.series.LineSerie
|
import com.dzeio.charts.series.LineSerie
|
||||||
import com.dzeio.openhealth.core.BaseFragment
|
import com.dzeio.openhealth.core.BaseFragment
|
||||||
import com.dzeio.openhealth.data.water.Water
|
import com.dzeio.openhealth.data.water.Water
|
||||||
@ -156,6 +158,13 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
|||||||
}
|
}
|
||||||
serie.entries = entries
|
serie.entries = entries
|
||||||
|
|
||||||
|
if (viewModel.goalWeight.value != null) {
|
||||||
|
chart.yAxis.addLine(
|
||||||
|
viewModel.goalWeight.value!!,
|
||||||
|
Line(true, Paint(chart.yAxis.linePaint).apply { strokeWidth = 4f })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
chart.xAxis.x = 0.0
|
chart.xAxis.x = 0.0
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package com.dzeio.openhealth.ui.steps
|
package com.dzeio.openhealth.ui.steps
|
||||||
|
|
||||||
|
import android.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.dzeio.charts.Entry
|
import com.dzeio.charts.Entry
|
||||||
import com.dzeio.charts.axis.Line
|
import com.dzeio.charts.axis.Line
|
||||||
@ -11,6 +14,7 @@ import com.dzeio.charts.series.BarSerie
|
|||||||
import com.dzeio.openhealth.Application
|
import com.dzeio.openhealth.Application
|
||||||
import com.dzeio.openhealth.adapters.StepsAdapter
|
import com.dzeio.openhealth.adapters.StepsAdapter
|
||||||
import com.dzeio.openhealth.core.BaseFragment
|
import com.dzeio.openhealth.core.BaseFragment
|
||||||
|
import com.dzeio.openhealth.data.step.Step
|
||||||
import com.dzeio.openhealth.databinding.FragmentStepsHomeBinding
|
import com.dzeio.openhealth.databinding.FragmentStepsHomeBinding
|
||||||
import com.dzeio.openhealth.utils.ChartUtils
|
import com.dzeio.openhealth.utils.ChartUtils
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
@ -29,6 +33,8 @@ class StepsHomeFragment :
|
|||||||
const val TAG = "${Application.TAG}/SHFragment"
|
const val TAG = "${Application.TAG}/SHFragment"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val args: StepsHomeFragmentArgs by navArgs()
|
||||||
|
|
||||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentStepsHomeBinding =
|
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentStepsHomeBinding =
|
||||||
FragmentStepsHomeBinding::inflate
|
FragmentStepsHomeBinding::inflate
|
||||||
|
|
||||||
@ -37,18 +43,26 @@ class StepsHomeFragment :
|
|||||||
|
|
||||||
viewModel.init()
|
viewModel.init()
|
||||||
|
|
||||||
|
val isDay = args.day > 0L
|
||||||
|
|
||||||
val recycler = binding.list
|
val recycler = binding.list
|
||||||
|
|
||||||
val manager = LinearLayoutManager(requireContext())
|
val manager = LinearLayoutManager(requireContext())
|
||||||
recycler.layoutManager = manager
|
recycler.layoutManager = manager
|
||||||
|
|
||||||
val adapter = StepsAdapter()
|
val adapter = StepsAdapter().apply {
|
||||||
adapter.onItemClick = {
|
this.isDay = isDay
|
||||||
// findNavController().navigate(
|
}
|
||||||
// WaterHomeFragmentDirections.actionNavWaterHomeToNavWaterEdit(
|
|
||||||
// it.id
|
if (!isDay) {
|
||||||
// )
|
adapter.onItemClick = {
|
||||||
// )
|
findNavController().navigate(
|
||||||
|
StepsHomeFragmentDirections.actionNavStepsHomeSelf().apply {
|
||||||
|
day = it.timestamp
|
||||||
|
title = "Steps from " + it.formatTimestamp(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
|
|
||||||
@ -64,69 +78,103 @@ class StepsHomeFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
xAxis.apply {
|
xAxis.apply {
|
||||||
dataWidth = 604800000.0
|
dataWidth = if (isDay) 8.64e+7 else 6.048e+8
|
||||||
|
scrollEnabled = !isDay
|
||||||
textPaint.textSize = 32f
|
textPaint.textSize = 32f
|
||||||
onValueFormat = onValueFormat@{
|
onValueFormat = onValueFormat@{
|
||||||
val formatter = DateFormat.getDateInstance(
|
val formatter = if (isDay) {
|
||||||
DateFormat.SHORT,
|
DateFormat.getTimeInstance(
|
||||||
Locale.getDefault()
|
DateFormat.SHORT,
|
||||||
)
|
Locale.getDefault()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
DateFormat.getDateInstance(
|
||||||
|
DateFormat.SHORT,
|
||||||
|
Locale.getDefault()
|
||||||
|
)
|
||||||
|
}
|
||||||
return@onValueFormat formatter.format(Date(it.toLong()))
|
return@onValueFormat formatter.format(Date(it.toLong()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
annotator.annotationTitleFormat = { "${it.y.roundToInt()} steps" }
|
annotator.annotationTitleFormat = { "${it.y.roundToInt()} steps" }
|
||||||
annotator.annotationSubTitleFormat = annotationSubTitleFormat@{
|
annotator.annotationSubTitleFormat = annotationSubTitleFormat@{
|
||||||
val formatter = DateFormat.getDateInstance(
|
val formatter = if (isDay) {
|
||||||
DateFormat.SHORT,
|
DateFormat.getTimeInstance(
|
||||||
Locale.getDefault()
|
DateFormat.SHORT,
|
||||||
)
|
Locale.getDefault()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
DateFormat.getDateInstance(
|
||||||
|
DateFormat.SHORT,
|
||||||
|
Locale.getDefault()
|
||||||
|
)
|
||||||
|
}
|
||||||
return@annotationSubTitleFormat formatter.format(Date(it.x.toLong()))
|
return@annotationSubTitleFormat formatter.format(Date(it.x.toLong()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.goal.observe(viewLifecycleOwner) {
|
viewModel.goal.observe(viewLifecycleOwner) {
|
||||||
if (it != null) {
|
if (it != null && !isDay) {
|
||||||
chart.yAxis.addLine(it.toFloat(), Line(true))
|
chart.yAxis.addLine(
|
||||||
|
it.toFloat(),
|
||||||
|
Line(true, Paint(chart.yAxis.linePaint).apply { strokeWidth = 4f })
|
||||||
|
)
|
||||||
chart.refresh()
|
chart.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.items.observe(viewLifecycleOwner) { list ->
|
viewModel.items.observe(viewLifecycleOwner) { list ->
|
||||||
adapter.set(list)
|
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
|
adapter.set(arrayListOf())
|
||||||
return@observe
|
return@observe
|
||||||
}
|
}
|
||||||
|
|
||||||
// chart.scroller.zoomEnabled = false
|
val filtered = if (!isDay) list else list.filter {
|
||||||
|
it.getDay() == args.day
|
||||||
|
}
|
||||||
|
if (isDay) {
|
||||||
|
adapter.set(filtered)
|
||||||
|
serie.entries = filtered.map {
|
||||||
|
Entry(
|
||||||
|
it.timestamp.toDouble(),
|
||||||
|
it.value.toFloat()
|
||||||
|
)
|
||||||
|
} as ArrayList<Entry>
|
||||||
|
} else {
|
||||||
|
val entries: HashMap<Long, Entry> = HashMap()
|
||||||
|
|
||||||
val entries: HashMap<Long, Entry> = HashMap()
|
list.forEach {
|
||||||
|
val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
||||||
|
cal.timeInMillis = it.timestamp
|
||||||
|
|
||||||
list.forEach {
|
cal.set(Calendar.HOUR, 0)
|
||||||
val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
|
cal.set(Calendar.AM_PM, Calendar.AM)
|
||||||
cal.timeInMillis = it.timestamp
|
val ts = cal.timeInMillis
|
||||||
|
if (!entries.containsKey(ts)) {
|
||||||
|
entries[ts] = Entry((ts).toDouble(), 0F, chart.yAxis.goalLinePaint.color)
|
||||||
|
}
|
||||||
|
|
||||||
cal.set(Calendar.HOUR, 0)
|
entries[ts]!!.y += it.value.toFloat()
|
||||||
cal.set(Calendar.AM_PM, Calendar.AM)
|
|
||||||
val ts = cal.timeInMillis
|
|
||||||
if (!entries.containsKey(ts)) {
|
|
||||||
entries[ts] = Entry((ts).toDouble(), 0F, chart.yAxis.goalLinePaint.color)
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[ts]!!.y += it.value.toFloat()
|
if (viewModel.goal.value != null) {
|
||||||
|
if (entries[ts]!!.y > viewModel.goal.value!!) {
|
||||||
if (viewModel.goal.value != null) {
|
entries[ts]!!.color = null
|
||||||
if (entries[ts]!!.y > viewModel.goal.value!!) {
|
}
|
||||||
|
} else {
|
||||||
entries[ts]!!.color = null
|
entries[ts]!!.color = null
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
entries[ts]!!.color = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adapter.set(
|
||||||
|
entries.map { Step(value = it.value.y.toInt(), timestamp = it.key) }
|
||||||
|
.sortedByDescending { it.timestamp }
|
||||||
|
)
|
||||||
|
|
||||||
|
serie.entries = ArrayList(entries.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
serie.entries = ArrayList(entries.values)
|
chart.xAxis.x =
|
||||||
|
chart.xAxis.getXMax() - chart.xAxis.dataWidth!! + chart.xAxis.dataWidth!! / (if (isDay) 24 else 7)
|
||||||
chart.xAxis.x = chart.xAxis.getXMin()
|
|
||||||
|
|
||||||
chart.refresh()
|
chart.refresh()
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
package com.dzeio.openhealth.ui.weight
|
package com.dzeio.openhealth.ui.weight
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.dzeio.charts.Entry
|
import com.dzeio.charts.Entry
|
||||||
|
import com.dzeio.charts.axis.Line
|
||||||
import com.dzeio.charts.series.LineSerie
|
import com.dzeio.charts.series.LineSerie
|
||||||
import com.dzeio.openhealth.R
|
import com.dzeio.openhealth.R
|
||||||
import com.dzeio.openhealth.adapters.WeightAdapter
|
import com.dzeio.openhealth.adapters.WeightAdapter
|
||||||
@ -37,8 +41,27 @@ class ListWeightFragment :
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
// FIXME: deprecated
|
// Menu
|
||||||
setHasOptionsMenu(true)
|
requireActivity().addMenuProvider(object : MenuProvider {
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
menu.findItem(R.id.action_add).isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
R.id.action_add -> {
|
||||||
|
findNavController().navigate(
|
||||||
|
ListWeightFragmentDirections.actionNavListWeightToNavWeightDialog(
|
||||||
|
WeightDialog.DialogTypes.ADD_WEIGHT.ordinal
|
||||||
|
)
|
||||||
|
)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if (viewModel.goalWeight.value != null) {
|
if (viewModel.goalWeight.value != null) {
|
||||||
binding.goalButton.setText(R.string.edit_goal)
|
binding.goalButton.setText(R.string.edit_goal)
|
||||||
@ -46,7 +69,9 @@ class ListWeightFragment :
|
|||||||
|
|
||||||
binding.goalButton.setOnClickListener {
|
binding.goalButton.setOnClickListener {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
ListWeightFragmentDirections.actionNavListWeightToNavWeightDialog(WeightDialog.DialogTypes.EDIT_GOAL.ordinal)
|
ListWeightFragmentDirections.actionNavListWeightToNavWeightDialog(
|
||||||
|
WeightDialog.DialogTypes.EDIT_GOAL.ordinal
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +135,6 @@ class ListWeightFragment :
|
|||||||
|
|
||||||
xAxis.apply {
|
xAxis.apply {
|
||||||
// 7 day history
|
// 7 day history
|
||||||
dataWidth = (7 * 24 * 60 * 60 * 1000).toDouble()
|
|
||||||
textPaint.color = MaterialColors.getColor(
|
textPaint.color = MaterialColors.getColor(
|
||||||
requireView(),
|
requireView(),
|
||||||
com.google.android.material.R.attr.colorOnPrimaryContainer
|
com.google.android.material.R.attr.colorOnPrimaryContainer
|
||||||
@ -128,15 +152,15 @@ class ListWeightFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debug button
|
// Debug button
|
||||||
if (binding.debugRandomValues != null) {
|
// if (binding.debugRandomValues != null) {
|
||||||
binding.debugRandomValues.setOnClickListener {
|
// binding.debugRandomValues.setOnClickListener {
|
||||||
viewModel.generateRandomValues()
|
// viewModel.generateRandomValues()
|
||||||
}
|
// }
|
||||||
binding.debugRandomValues.setOnLongClickListener {
|
// binding.debugRandomValues.setOnLongClickListener {
|
||||||
viewModel.delete(viewModel.weights.value!!)
|
// viewModel.delete(viewModel.weights.value!!)
|
||||||
return@setOnLongClickListener true
|
// return@setOnLongClickListener true
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateGraph(list: List<Weight>) {
|
private fun updateGraph(list: List<Weight>) {
|
||||||
@ -146,13 +170,22 @@ class ListWeightFragment :
|
|||||||
val entries: ArrayList<Entry> = arrayListOf()
|
val entries: ArrayList<Entry> = arrayListOf()
|
||||||
|
|
||||||
list.forEach {
|
list.forEach {
|
||||||
entries.add(Entry(
|
entries.add(
|
||||||
it.timestamp.toDouble(),
|
Entry(
|
||||||
it.weight
|
it.timestamp.toDouble(),
|
||||||
))
|
it.weight
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
serie.entries = entries
|
serie.entries = entries
|
||||||
|
|
||||||
|
if (viewModel.goalWeight.value != null) {
|
||||||
|
chart.yAxis.addLine(
|
||||||
|
viewModel.goalWeight.value!!,
|
||||||
|
Line(true, Paint(chart.yAxis.linePaint).apply { strokeWidth = 4f })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
chart.xAxis.x = 0.0
|
chart.xAxis.x = 0.0
|
||||||
} else {
|
} else {
|
||||||
@ -161,27 +194,4 @@ class ListWeightFragment :
|
|||||||
|
|
||||||
chart.refresh()
|
chart.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
|
||||||
menu.findItem(R.id.action_add).isVisible = true
|
|
||||||
|
|
||||||
super.onPrepareOptionsMenu(menu)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
return when (item.itemId) {
|
|
||||||
R.id.action_add -> {
|
|
||||||
findNavController().navigate(
|
|
||||||
ListWeightFragmentDirections.actionNavListWeightToNavWeightDialog(
|
|
||||||
WeightDialog.DialogTypes.ADD_WEIGHT.ordinal
|
|
||||||
)
|
|
||||||
)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ class ListWeightViewModel @Inject internal constructor(
|
|||||||
private val settings: Configuration
|
private val settings: Configuration
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
|
||||||
private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM)
|
private val _massUnit = MutableLiveData(Units.Mass.KILOGRAM)
|
||||||
val massUnit: LiveData<Units.Mass> = _massUnit
|
val massUnit: LiveData<Units.Mass> = _massUnit
|
||||||
|
|
||||||
@ -31,7 +30,6 @@ class ListWeightViewModel @Inject internal constructor(
|
|||||||
private val _weights = MutableLiveData<List<Weight>?>(null)
|
private val _weights = MutableLiveData<List<Weight>?>(null)
|
||||||
val weights: LiveData<List<Weight>?> = _weights
|
val weights: LiveData<List<Weight>?> = _weights
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
weightRepository.getWeights().collectLatest {
|
weightRepository.getWeights().collectLatest {
|
||||||
@ -50,7 +48,7 @@ class ListWeightViewModel @Inject internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateRandomValues(): Unit {
|
fun generateRandomValues() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
weightRepository.addWeight(
|
weightRepository.addWeight(
|
||||||
Weight(
|
Weight(
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package com.dzeio.openhealth.utils
|
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.os.AsyncTask
|
|
||||||
import android.util.Log
|
|
||||||
import android.widget.ImageView
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stolen from StackOverflow https://stackoverflow.com/a/10868126/7335674
|
|
||||||
*
|
|
||||||
* Allows to download an image asynchronously
|
|
||||||
*
|
|
||||||
* TODO: rework so it is not deprecated anymore
|
|
||||||
*/
|
|
||||||
class DownloadImageTask(var bmImage: ImageView) :
|
|
||||||
AsyncTask<String?, Void?, Bitmap?>() {
|
|
||||||
@Deprecated("Deprecated in Java")
|
|
||||||
override fun doInBackground(vararg urls: String?): Bitmap? {
|
|
||||||
val urldisplay = urls[0]
|
|
||||||
var mIcon11: Bitmap? = null
|
|
||||||
try {
|
|
||||||
val `in` = URL(urldisplay).openStream()
|
|
||||||
mIcon11 = BitmapFactory.decodeStream(`in`)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("Error", e.message!!)
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
return mIcon11
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java", ReplaceWith("bmImage.setImageBitmap(result)"))
|
|
||||||
override fun onPostExecute(result: Bitmap?) {
|
|
||||||
bmImage.setImageBitmap(result)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.dzeio.openhealth.utils
|
||||||
|
|
||||||
|
data class NetworkResult<T>(
|
||||||
|
var status: NetworkStatus = NetworkStatus.RUNNING,
|
||||||
|
var data: T? = null
|
||||||
|
) {
|
||||||
|
enum class NetworkStatus {
|
||||||
|
RUNNING,
|
||||||
|
FINISHED,
|
||||||
|
ERRORED
|
||||||
|
}
|
||||||
|
}
|
39
app/src/main/java/com/dzeio/openhealth/utils/NetworkUtils.kt
Normal file
39
app/src/main/java/com/dzeio/openhealth/utils/NetworkUtils.kt
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.dzeio.openhealth.utils
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.ImageView
|
||||||
|
import java.net.URL
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
object NetworkUtils {
|
||||||
|
/**
|
||||||
|
* Fetch an image and apply it to an [image] [ImageView]
|
||||||
|
*
|
||||||
|
* Adapted from https://stackoverflow.com/a/10868126/7335674
|
||||||
|
* to not be deprecated
|
||||||
|
*
|
||||||
|
* @param image the ImageView
|
||||||
|
* @param url the url to fetch the image from
|
||||||
|
*/
|
||||||
|
fun getImageInBackground(image: ImageView, url: String) {
|
||||||
|
val executor = Executors.newSingleThreadExecutor()
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
executor.execute {
|
||||||
|
var bitmap: Bitmap? = null
|
||||||
|
try {
|
||||||
|
val `in` = URL(url).openStream()
|
||||||
|
bitmap = BitmapFactory.decodeStream(`in`)
|
||||||
|
handler.post {
|
||||||
|
image.setImageBitmap(bitmap)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("Error", e.message!!)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
app/src/main/res/drawable/ic_zoom_out_map.xml
Normal file
5
app/src/main/res/drawable/ic_zoom_out_map.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M15,3l2.3,2.3l-2.89,2.87l1.42,1.42L18.7,6.7L21,9V3H15zM3,9l2.3,-2.3l2.87,2.89l1.42,-1.42L6.7,5.3L9,3H3V9zM9,21l-2.3,-2.3l2.89,-2.87l-1.42,-1.42L5.3,17.3L3,15v6H9zM21,15l-2.3,2.3l-2.87,-2.89l-1.42,1.42l2.89,2.87L15,21h6V15z"/>
|
||||||
|
</vector>
|
@ -19,12 +19,21 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/error_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/connectivity_error" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/list"
|
android:id="@+id/list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:itemCount="5"
|
tools:itemCount="5"
|
||||||
tools:listitem="@layout/item_food"/>
|
tools:listitem="@layout/item_food">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.github.mikephil.charting.charts.LineChart
|
<com.dzeio.charts.ChartView
|
||||||
android:id="@+id/chart"
|
android:id="@+id/chart"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
style="?attr/materialCardViewFilledStyle"
|
style="?attr/materialCardViewFilledStyle"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
@ -41,10 +39,11 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:id="@+id/icon_right"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:src="@drawable/ic_baseline_edit_24" />
|
android:src="@drawable/ic_baseline_edit_24" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
@ -134,9 +134,23 @@
|
|||||||
tools:layout="@layout/fragment_activity" />
|
tools:layout="@layout/fragment_activity" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_steps_home"
|
android:id="@+id/nav_steps_home"
|
||||||
|
android:label="{title}"
|
||||||
android:name="com.dzeio.openhealth.ui.steps.StepsHomeFragment"
|
android:name="com.dzeio.openhealth.ui.steps.StepsHomeFragment"
|
||||||
android:label="@string/menu_steps"
|
tools:layout="@layout/fragment_steps_home" >
|
||||||
tools:layout="@layout/fragment_steps_home" />
|
<argument
|
||||||
|
android:name="day"
|
||||||
|
app:argType="long"
|
||||||
|
android:defaultValue="-1L"
|
||||||
|
/>
|
||||||
|
<argument
|
||||||
|
android:name="title"
|
||||||
|
app:argType="string"
|
||||||
|
android:defaultValue="Steps"
|
||||||
|
/>
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_nav_steps_home_self"
|
||||||
|
app:destination="@id/nav_steps_home" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
<dialog
|
<dialog
|
||||||
android:id="@+id/nav_weight_dialog"
|
android:id="@+id/nav_weight_dialog"
|
||||||
|
@ -54,5 +54,6 @@
|
|||||||
<string name="steps_taken">Pas pris</string>
|
<string name="steps_taken">Pas pris</string>
|
||||||
<string name="error_reporter_crash">Erreur lors de la géneration d\'un rapport d\'erreur</string>
|
<string name="error_reporter_crash">Erreur lors de la géneration d\'un rapport d\'erreur</string>
|
||||||
<string name="steps_count">%1$d pas</string>
|
<string name="steps_count">%1$d pas</string>
|
||||||
|
<string name="connectivity_error">Il semplerais que nous ne pouvons pas communiquer avec OpenFoodFact, Merci de re-essayer plus tard</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -67,4 +67,5 @@
|
|||||||
<string name="error_reporter_crash">An error occurred while making the error report</string>
|
<string name="error_reporter_crash">An error occurred while making the error report</string>
|
||||||
<string name="food_description" translatable="false">%1$s (%2$.0f kcal)</string>
|
<string name="food_description" translatable="false">%1$s (%2$.0f kcal)</string>
|
||||||
<string name="steps_count">%1$d steps</string>
|
<string name="steps_count">%1$d steps</string>
|
||||||
|
<string name="connectivity_error">It seems that we can\'t communicate with OpenFoodFact, please retry later</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -14,9 +14,9 @@ buildscript {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
// android app plugin ? (tbh idk what thoses "plugins" does)
|
// android app plugin ? (tbh idk what thoses "plugins" does)
|
||||||
id("com.android.application") version "7.3.1" apply false
|
id("com.android.application") version "7.4.0" apply false
|
||||||
// is it a lib? no, do I need it? IDK
|
// is it a lib? no, do I need it? IDK
|
||||||
id("com.android.library") version "7.3.1" apply false
|
id("com.android.library") version "7.4.0" apply false
|
||||||
|
|
||||||
// add kotlin compatibility :>
|
// add kotlin compatibility :>
|
||||||
id("org.jetbrains.kotlin.android") version "1.8.0" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.0" apply false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user