NSCv3: process Food, first load based on created_at
This commit is contained in:
parent
10e8e32e3b
commit
d9c6cd6342
25 changed files with 603 additions and 159 deletions
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.workflow
|
package info.nightscout.androidaps.workflow
|
||||||
|
|
||||||
import info.nightscout.interfaces.workflow.WorkerClasses
|
import info.nightscout.interfaces.workflow.WorkerClasses
|
||||||
import info.nightscout.plugins.general.food.FoodPlugin
|
|
||||||
import info.nightscout.plugins.profile.ProfilePlugin
|
import info.nightscout.plugins.profile.ProfilePlugin
|
||||||
import info.nightscout.source.NSClientSourcePlugin
|
import info.nightscout.source.NSClientSourcePlugin
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -10,5 +9,4 @@ class WorkerClassesImpl @Inject constructor(): WorkerClasses{
|
||||||
|
|
||||||
override val nsClientSourceWorker = NSClientSourcePlugin.NSClientSourceWorker::class.java
|
override val nsClientSourceWorker = NSClientSourcePlugin.NSClientSourceWorker::class.java
|
||||||
override val nsProfileWorker = ProfilePlugin.NSProfileWorker::class.java
|
override val nsProfileWorker = ProfilePlugin.NSProfileWorker::class.java
|
||||||
override val foodWorker = FoodPlugin.FoodWorker::class.java
|
|
||||||
}
|
}
|
1
connectwsa.bat
Normal file
1
connectwsa.bat
Normal file
|
@ -0,0 +1 @@
|
||||||
|
adb connect 127.0.0.1:58526
|
|
@ -27,11 +27,11 @@ interface StoreDataForDb {
|
||||||
val temporaryBasals: MutableList<TemporaryBasal>
|
val temporaryBasals: MutableList<TemporaryBasal>
|
||||||
val profileSwitches: MutableList<ProfileSwitch>
|
val profileSwitches: MutableList<ProfileSwitch>
|
||||||
val offlineEvents: MutableList<OfflineEvent>
|
val offlineEvents: MutableList<OfflineEvent>
|
||||||
|
val foods: MutableList<Food>
|
||||||
|
|
||||||
val nsIdGlucoseValues: MutableList<GlucoseValue>
|
val nsIdGlucoseValues: MutableList<GlucoseValue>
|
||||||
val nsIdBoluses: MutableList<Bolus>
|
val nsIdBoluses: MutableList<Bolus>
|
||||||
val nsIdCarbs: MutableList<Carbs>
|
val nsIdCarbs: MutableList<Carbs>
|
||||||
val nsIdFoods: MutableList<Food>
|
|
||||||
val nsIdTemporaryTargets: MutableList<TemporaryTarget>
|
val nsIdTemporaryTargets: MutableList<TemporaryTarget>
|
||||||
val nsIdEffectiveProfileSwitches: MutableList<EffectiveProfileSwitch>
|
val nsIdEffectiveProfileSwitches: MutableList<EffectiveProfileSwitch>
|
||||||
val nsIdBolusCalculatorResults: MutableList<BolusCalculatorResult>
|
val nsIdBolusCalculatorResults: MutableList<BolusCalculatorResult>
|
||||||
|
@ -41,8 +41,10 @@ interface StoreDataForDb {
|
||||||
val nsIdProfileSwitches: MutableList<ProfileSwitch>
|
val nsIdProfileSwitches: MutableList<ProfileSwitch>
|
||||||
val nsIdOfflineEvents: MutableList<OfflineEvent>
|
val nsIdOfflineEvents: MutableList<OfflineEvent>
|
||||||
val nsIdDeviceStatuses: MutableList<DeviceStatus>
|
val nsIdDeviceStatuses: MutableList<DeviceStatus>
|
||||||
|
val nsIdFoods: MutableList<Food>
|
||||||
|
|
||||||
fun storeTreatmentsToDb()
|
fun storeTreatmentsToDb()
|
||||||
fun storeGlucoseValuesToDb()
|
fun storeGlucoseValuesToDb()
|
||||||
|
fun storeFoodsToDb()
|
||||||
fun scheduleNsIdUpdate()
|
fun scheduleNsIdUpdate()
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@ interface NsClient : Sync {
|
||||||
fun textLog(): Spanned
|
fun textLog(): Spanned
|
||||||
fun clearLog()
|
fun clearLog()
|
||||||
|
|
||||||
enum class Collection { ENTRIES, TREATMENTS}
|
enum class Collection { ENTRIES, TREATMENTS, FOODS }
|
||||||
/**
|
/**
|
||||||
* NSC v3 does first load of all data
|
* NSC v3 does first load of all data
|
||||||
* next loads are using srvModified property for sync
|
* next loads are using srvModified property for sync
|
||||||
|
|
|
@ -5,5 +5,4 @@ import androidx.work.ListenableWorker
|
||||||
interface WorkerClasses {
|
interface WorkerClasses {
|
||||||
val nsClientSourceWorker: Class<out ListenableWorker>
|
val nsClientSourceWorker: Class<out ListenableWorker>
|
||||||
val nsProfileWorker: Class<out ListenableWorker>
|
val nsProfileWorker: Class<out ListenableWorker>
|
||||||
val foodWorker: Class<out ListenableWorker>
|
|
||||||
}
|
}
|
|
@ -4,14 +4,17 @@ import android.content.Context
|
||||||
import info.nightscout.sdk.exceptions.DateHeaderOutOfToleranceException
|
import info.nightscout.sdk.exceptions.DateHeaderOutOfToleranceException
|
||||||
import info.nightscout.sdk.exceptions.InvalidAccessTokenException
|
import info.nightscout.sdk.exceptions.InvalidAccessTokenException
|
||||||
import info.nightscout.sdk.exceptions.InvalidFormatNightscoutException
|
import info.nightscout.sdk.exceptions.InvalidFormatNightscoutException
|
||||||
import info.nightscout.sdk.exceptions.UnsuccessfullNightscoutException
|
|
||||||
import info.nightscout.sdk.exceptions.UnknownResponseNightscoutException
|
import info.nightscout.sdk.exceptions.UnknownResponseNightscoutException
|
||||||
|
import info.nightscout.sdk.exceptions.UnsuccessfullNightscoutException
|
||||||
import info.nightscout.sdk.interfaces.NSAndroidClient
|
import info.nightscout.sdk.interfaces.NSAndroidClient
|
||||||
import info.nightscout.sdk.localmodel.Status
|
import info.nightscout.sdk.localmodel.Status
|
||||||
import info.nightscout.sdk.localmodel.entry.NSSgvV3
|
import info.nightscout.sdk.localmodel.entry.NSSgvV3
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
|
import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
|
||||||
import info.nightscout.sdk.localmodel.treatment.NSTreatment
|
import info.nightscout.sdk.localmodel.treatment.NSTreatment
|
||||||
import info.nightscout.sdk.mapper.toLocal
|
import info.nightscout.sdk.mapper.toLocal
|
||||||
|
import info.nightscout.sdk.mapper.toNSFood
|
||||||
|
import info.nightscout.sdk.mapper.toRemoteFood
|
||||||
import info.nightscout.sdk.mapper.toRemoteTreatment
|
import info.nightscout.sdk.mapper.toRemoteTreatment
|
||||||
import info.nightscout.sdk.mapper.toSgv
|
import info.nightscout.sdk.mapper.toSgv
|
||||||
import info.nightscout.sdk.mapper.toTreatment
|
import info.nightscout.sdk.mapper.toTreatment
|
||||||
|
@ -19,6 +22,7 @@ import info.nightscout.sdk.networking.NetworkStackBuilder
|
||||||
import info.nightscout.sdk.remotemodel.LastModified
|
import info.nightscout.sdk.remotemodel.LastModified
|
||||||
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
|
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
|
||||||
import info.nightscout.sdk.remotemodel.RemoteEntry
|
import info.nightscout.sdk.remotemodel.RemoteEntry
|
||||||
|
import info.nightscout.sdk.remotemodel.RemoteFood
|
||||||
import info.nightscout.sdk.remotemodel.RemoteTreatment
|
import info.nightscout.sdk.remotemodel.RemoteTreatment
|
||||||
import info.nightscout.sdk.utils.retry
|
import info.nightscout.sdk.utils.retry
|
||||||
import info.nightscout.sdk.utils.toNotNull
|
import info.nightscout.sdk.utils.toNotNull
|
||||||
|
@ -140,9 +144,9 @@ class NSAndroidClientImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getTreatmentsNewerThan(from: Long, limit: Long): List<NSTreatment> = callWrapper(dispatcher) {
|
override suspend fun getTreatmentsNewerThan(createdAt: String, limit: Long): List<NSTreatment> = callWrapper(dispatcher) {
|
||||||
|
|
||||||
val response = api.getTreatmentsNewerThan(from, limit)
|
val response = api.getTreatmentsNewerThan(createdAt, limit)
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
return@callWrapper response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()
|
return@callWrapper response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()
|
||||||
} else {
|
} else {
|
||||||
|
@ -154,7 +158,8 @@ class NSAndroidClientImpl(
|
||||||
|
|
||||||
val response = api.getTreatmentsModifiedSince(from, limit)
|
val response = api.getTreatmentsModifiedSince(from, limit)
|
||||||
val eTagString = response.headers()["ETag"]
|
val eTagString = response.headers()["ETag"]
|
||||||
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException()
|
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong()
|
||||||
|
?: throw UnsuccessfullNightscoutException()
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull())
|
return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull())
|
||||||
} else {
|
} else {
|
||||||
|
@ -207,6 +212,64 @@ class NSAndroidClientImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getFoods(limit: Long): List<NSFood> = callWrapper(dispatcher) {
|
||||||
|
|
||||||
|
val response = api.getFoods(limit)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
return@callWrapper response.body()?.result?.map(RemoteFood::toNSFood).toNotNull()
|
||||||
|
} else {
|
||||||
|
throw UnsuccessfullNightscoutException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
override suspend fun getFoodsModifiedSince(from: Long, limit: Long): NSAndroidClient.ReadResponse<List<NSFood>> = callWrapper(dispatcher) {
|
||||||
|
|
||||||
|
val response = api.getFoodsModifiedSince(from, limit)
|
||||||
|
val eTagString = response.headers()["ETag"]
|
||||||
|
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException()
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteFood::toNSFood).toNotNull())
|
||||||
|
} else {
|
||||||
|
throw UnsuccessfullNightscoutException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
override suspend fun createFood(nsFood: NSFood): CreateUpdateResponse = callWrapper(dispatcher) {
|
||||||
|
|
||||||
|
val remoteFood = nsFood.toRemoteFood()
|
||||||
|
remoteFood.app = "AAPS"
|
||||||
|
val response = api.createFood(remoteFood)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
return@callWrapper CreateUpdateResponse(
|
||||||
|
response = response.code(),
|
||||||
|
identifier = response.body()?.result?.identifier ?: throw UnknownResponseNightscoutException(),
|
||||||
|
isDeduplication = response.body()?.result?.isDeduplication ?: false,
|
||||||
|
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
|
||||||
|
lastModified = response.body()?.result?.lastModified
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw UnsuccessfullNightscoutException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateFood(nsFood: NSFood): CreateUpdateResponse = callWrapper(dispatcher) {
|
||||||
|
|
||||||
|
val remoteFood = nsFood.toRemoteFood()
|
||||||
|
val response = api.updateFood(remoteFood)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
return@callWrapper CreateUpdateResponse(
|
||||||
|
response = response.code(),
|
||||||
|
identifier = response.body()?.result?.identifier ?: throw UnknownResponseNightscoutException(),
|
||||||
|
isDeduplication = response.body()?.result?.isDeduplication ?: false,
|
||||||
|
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
|
||||||
|
lastModified = response.body()?.result?.lastModified
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw UnsuccessfullNightscoutException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T =
|
private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T =
|
||||||
withContext(dispatcher) {
|
withContext(dispatcher) {
|
||||||
retry(
|
retry(
|
||||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.sdk.interfaces
|
||||||
|
|
||||||
import info.nightscout.sdk.localmodel.Status
|
import info.nightscout.sdk.localmodel.Status
|
||||||
import info.nightscout.sdk.localmodel.entry.NSSgvV3
|
import info.nightscout.sdk.localmodel.entry.NSSgvV3
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
|
import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
|
||||||
import info.nightscout.sdk.localmodel.treatment.NSTreatment
|
import info.nightscout.sdk.localmodel.treatment.NSTreatment
|
||||||
import info.nightscout.sdk.remotemodel.LastModified
|
import info.nightscout.sdk.remotemodel.LastModified
|
||||||
|
@ -23,9 +24,13 @@ interface NSAndroidClient {
|
||||||
suspend fun getSgvs(): List<NSSgvV3>
|
suspend fun getSgvs(): List<NSSgvV3>
|
||||||
suspend fun getSgvsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSSgvV3>>
|
suspend fun getSgvsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSSgvV3>>
|
||||||
suspend fun getSgvsNewerThan(from: Long, limit: Long): List<NSSgvV3>
|
suspend fun getSgvsNewerThan(from: Long, limit: Long): List<NSSgvV3>
|
||||||
suspend fun getTreatmentsNewerThan(from: Long, limit: Long): List<NSTreatment>
|
suspend fun getTreatmentsNewerThan(createdAt: String, limit: Long): List<NSTreatment>
|
||||||
suspend fun getTreatmentsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSTreatment>>
|
suspend fun getTreatmentsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSTreatment>>
|
||||||
suspend fun getDeviceStatusModifiedSince(from: Long): List<RemoteDeviceStatus>
|
suspend fun getDeviceStatusModifiedSince(from: Long): List<RemoteDeviceStatus>
|
||||||
suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse
|
suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse
|
||||||
suspend fun updateTreatment(nsTreatment: NSTreatment): CreateUpdateResponse
|
suspend fun updateTreatment(nsTreatment: NSTreatment): CreateUpdateResponse
|
||||||
|
suspend fun getFoods(limit: Long): List<NSFood>
|
||||||
|
//suspend fun getFoodsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSFood>>
|
||||||
|
suspend fun createFood(nsFood: NSFood): CreateUpdateResponse
|
||||||
|
suspend fun updateFood(nsFood: NSFood): CreateUpdateResponse
|
||||||
}
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package info.nightscout.sdk.localmodel.food
|
||||||
|
|
||||||
|
import info.nightscout.sdk.localmodel.entry.NsUnits
|
||||||
|
|
||||||
|
data class NSFood(
|
||||||
|
val date: Long,
|
||||||
|
val device: String? = null,
|
||||||
|
val identifier: String?,
|
||||||
|
val units: NsUnits? = null,
|
||||||
|
val srvModified: Long? = null,
|
||||||
|
val srvCreated: Long? = null,
|
||||||
|
val subject: String? = null,
|
||||||
|
var isReadOnly: Boolean = false,
|
||||||
|
val isValid: Boolean,
|
||||||
|
var app: String? = null,
|
||||||
|
var name: String,
|
||||||
|
var category: String? = null,
|
||||||
|
var subCategory: String? = null,
|
||||||
|
// Example:
|
||||||
|
// name="juice" portion=250 units="ml" carbs=12
|
||||||
|
// means 250ml of juice has 12g of carbs
|
||||||
|
|
||||||
|
var portion: Double, // common portion in "units"
|
||||||
|
var carbs: Int, // in grams
|
||||||
|
var fat: Int? = null, // in grams
|
||||||
|
var protein: Int? = null, // in grams
|
||||||
|
var energy: Int? = null, // in kJ
|
||||||
|
var unit: String = "g",
|
||||||
|
var gi: Int? = null // not used yet
|
||||||
|
)
|
|
@ -34,6 +34,7 @@ enum class EventType(val text: String) {
|
||||||
@SerializedName("Temp Basal Start") TEMPORARY_BASAL_START("Temp Basal Start"),
|
@SerializedName("Temp Basal Start") TEMPORARY_BASAL_START("Temp Basal Start"),
|
||||||
@SerializedName("Temp Basal End") TEMPORARY_BASAL_END("Temp Basal End"),
|
@SerializedName("Temp Basal End") TEMPORARY_BASAL_END("Temp Basal End"),
|
||||||
|
|
||||||
|
@SerializedName("") ERROR(""),
|
||||||
@SerializedName("<none>") NONE("<none>");
|
@SerializedName("<none>") NONE("<none>");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package info.nightscout.sdk.mapper
|
||||||
|
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
|
import info.nightscout.sdk.remotemodel.RemoteFood
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to [RemoteFood] and back to [NSFood]
|
||||||
|
* testing purpose only
|
||||||
|
*
|
||||||
|
* @return treatment after double conversion
|
||||||
|
*/
|
||||||
|
fun NSFood.convertToRemoteAndBack(): NSFood? =
|
||||||
|
toRemoteFood().toNSFood()
|
||||||
|
|
||||||
|
internal fun RemoteFood.toNSFood(): NSFood? {
|
||||||
|
when (type) {
|
||||||
|
"food" ->
|
||||||
|
return NSFood(
|
||||||
|
date = date ?: 0L,
|
||||||
|
device = device,
|
||||||
|
identifier = identifier,
|
||||||
|
unit = unit ?: "g",
|
||||||
|
srvModified = srvModified,
|
||||||
|
srvCreated = srvCreated,
|
||||||
|
subject = subject,
|
||||||
|
isReadOnly = isReadOnly ?: false,
|
||||||
|
isValid = isValid ?: true,
|
||||||
|
name = name,
|
||||||
|
category = category,
|
||||||
|
subCategory = subcategory,
|
||||||
|
portion = portion,
|
||||||
|
carbs = carbs,
|
||||||
|
fat = fat,
|
||||||
|
protein = protein,
|
||||||
|
energy = energy,
|
||||||
|
gi = gi
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun NSFood.toRemoteFood(): RemoteFood =
|
||||||
|
RemoteFood(
|
||||||
|
type = "food",
|
||||||
|
date = date,
|
||||||
|
device = device,
|
||||||
|
identifier = identifier,
|
||||||
|
unit = unit,
|
||||||
|
srvModified = srvModified,
|
||||||
|
srvCreated = srvCreated,
|
||||||
|
subject = subject,
|
||||||
|
isReadOnly = isReadOnly,
|
||||||
|
isValid = isValid,
|
||||||
|
name = name,
|
||||||
|
category = category,
|
||||||
|
subcategory = subCategory,
|
||||||
|
portion = portion,
|
||||||
|
carbs = carbs,
|
||||||
|
fat = fat,
|
||||||
|
protein = protein,
|
||||||
|
energy = energy,
|
||||||
|
gi = gi
|
||||||
|
)
|
|
@ -6,6 +6,7 @@ import info.nightscout.sdk.remotemodel.NSResponse
|
||||||
import info.nightscout.sdk.remotemodel.RemoteCreateUpdateResponse
|
import info.nightscout.sdk.remotemodel.RemoteCreateUpdateResponse
|
||||||
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
|
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
|
||||||
import info.nightscout.sdk.remotemodel.RemoteEntry
|
import info.nightscout.sdk.remotemodel.RemoteEntry
|
||||||
|
import info.nightscout.sdk.remotemodel.RemoteFood
|
||||||
import info.nightscout.sdk.remotemodel.RemoteStatusResponse
|
import info.nightscout.sdk.remotemodel.RemoteStatusResponse
|
||||||
import info.nightscout.sdk.remotemodel.RemoteTreatment
|
import info.nightscout.sdk.remotemodel.RemoteTreatment
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
@ -48,7 +49,7 @@ internal interface NightscoutRemoteService {
|
||||||
suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteEntry>>>
|
suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteEntry>>>
|
||||||
|
|
||||||
@GET("v3/treatments")
|
@GET("v3/treatments")
|
||||||
suspend fun getTreatmentsNewerThan(@Query(value = "date\$gt", encoded = true) date: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteTreatment>>>
|
suspend fun getTreatmentsNewerThan(@Query(value = "created_at\$gt", encoded = true) createdAt: String, @Query("limit") limit: Long): Response<NSResponse<List<RemoteTreatment>>>
|
||||||
|
|
||||||
@GET("v3/treatments/history/{from}")
|
@GET("v3/treatments/history/{from}")
|
||||||
suspend fun getTreatmentsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteTreatment>>>
|
suspend fun getTreatmentsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteTreatment>>>
|
||||||
|
@ -62,4 +63,16 @@ internal interface NightscoutRemoteService {
|
||||||
@PUT("v3/treatments")
|
@PUT("v3/treatments")
|
||||||
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment): Response<NSResponse<RemoteCreateUpdateResponse>>
|
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment): Response<NSResponse<RemoteCreateUpdateResponse>>
|
||||||
|
|
||||||
|
@GET("v3/food")
|
||||||
|
suspend fun getFoods(@Query("limit") limit: Long): Response<NSResponse<List<RemoteFood>>>
|
||||||
|
/*
|
||||||
|
@GET("v3/food/history/{from}")
|
||||||
|
suspend fun getFoodsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteFood>>>
|
||||||
|
*/
|
||||||
|
@POST("v3/food")
|
||||||
|
suspend fun createFood(@Body remoteFood: RemoteFood): Response<NSResponse<RemoteCreateUpdateResponse>>
|
||||||
|
|
||||||
|
@PUT("v3/food")
|
||||||
|
suspend fun updateFood(@Body remoteFood: RemoteFood): Response<NSResponse<RemoteCreateUpdateResponse>>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ data class LastModified(
|
||||||
@SerializedName("devicestatus") var devicestatus: Long = 0, // devicestatus collection
|
@SerializedName("devicestatus") var devicestatus: Long = 0, // devicestatus collection
|
||||||
@SerializedName("entries") var entries: Long = 0, // entries collection
|
@SerializedName("entries") var entries: Long = 0, // entries collection
|
||||||
@SerializedName("profile") var profile: Long = 0, // profile collection
|
@SerializedName("profile") var profile: Long = 0, // profile collection
|
||||||
@SerializedName("treatments") var treatments: Long = 0 // treatments collection
|
@SerializedName("treatments") var treatments: Long = 0, // treatments collection
|
||||||
|
@SerializedName("foods") var foods: Long = 0 // foods collection
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package info.nightscout.sdk.remotemodel
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Depending on the type, different other fields are present.
|
||||||
|
* Those technically need to be optional.
|
||||||
|
*
|
||||||
|
* On upload a sanity check still needs to be done to verify that all mandatory fields for that type are there.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
internal data class RemoteFood(
|
||||||
|
@SerializedName("type") val type: String, // we are interesting in type "food"
|
||||||
|
@SerializedName("date") val date: Long?,
|
||||||
|
@SerializedName("name") val name: String,
|
||||||
|
@SerializedName("category") val category: String?,
|
||||||
|
@SerializedName("subcategory") val subcategory: String?,
|
||||||
|
@SerializedName("unit") val unit: String?,
|
||||||
|
@SerializedName("portion") val portion: Double,
|
||||||
|
@SerializedName("carbs") val carbs: Int,
|
||||||
|
@SerializedName("gi") val gi: Int?,
|
||||||
|
@SerializedName("energy") val energy: Int?,
|
||||||
|
@SerializedName("protein") val protein: Int?,
|
||||||
|
@SerializedName("fat") val fat: Int?,
|
||||||
|
@SerializedName("identifier")
|
||||||
|
val identifier: String?, // string Main addressing, required field that identifies document in the collection. The client should not create the identifier, the server automatically assigns it when the document is inserted.
|
||||||
|
@SerializedName("isValid")
|
||||||
|
val isValid: Boolean?, // A flag set by the server only for deleted documents. This field appears only within history operation and for documents which were deleted by API v3 (and they always have a false value)
|
||||||
|
@SerializedName("isReadOnly")
|
||||||
|
val isReadOnly: Boolean?, // A flag set by client that locks the document from any changes. Every document marked with isReadOnly=true is forever immutable and cannot even be deleted.
|
||||||
|
@SerializedName("app") var app: String? = null, // Application or system in which the record was entered by human or device for the first time.
|
||||||
|
@SerializedName("device") val device: String? = null, // string The device from which the data originated (including serial number of the device, if it is relevant and safe).
|
||||||
|
@SerializedName("srvCreated")
|
||||||
|
val srvCreated: Long? = null, // integer($int64) example: 1525383610088 The server's timestamp of document insertion into the database (Unix epoch in ms). This field appears only for documents which were inserted by API v3.
|
||||||
|
@SerializedName("subject")
|
||||||
|
val subject: String? = null, // string Name of the security subject (within Nightscout scope) which has created the document. This field is automatically set by the server from the passed token or JWT.
|
||||||
|
@SerializedName("srvModified")
|
||||||
|
val srvModified: Long? = null, // integer($int64) example: 1525383610088 The server's timestamp of the last document modification in the database (Unix epoch in ms). This field appears only for documents which were somehow modified by API v3 (inserted, updated or deleted).
|
||||||
|
@SerializedName("modifiedBy")
|
||||||
|
val modifiedBy: String? = null // string Name of the security subject (within Nightscout scope) which has patched or deleted the document for the last time. This field is automatically set by the server.
|
||||||
|
)
|
|
@ -3,32 +3,33 @@ package info.nightscout.database.impl.transactions
|
||||||
import info.nightscout.database.entities.Food
|
import info.nightscout.database.entities.Food
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync the TherapyEvents from NS
|
* Sync the Foods from NS
|
||||||
*/
|
*/
|
||||||
class SyncNsFoodTransaction(private val food: Food) : Transaction<SyncNsFoodTransaction.TransactionResult>() {
|
class SyncNsFoodTransaction(private val foods: List<Food>) : Transaction<SyncNsFoodTransaction.TransactionResult>() {
|
||||||
|
|
||||||
override fun run(): TransactionResult {
|
override fun run(): TransactionResult {
|
||||||
val result = TransactionResult()
|
val result = TransactionResult()
|
||||||
|
|
||||||
val current: Food? =
|
for (food in foods) {
|
||||||
food.interfaceIDs.nightscoutId?.let {
|
val current: Food? =
|
||||||
database.foodDao.findByNSId(it)
|
food.interfaceIDs.nightscoutId?.let {
|
||||||
}
|
database.foodDao.findByNSId(it)
|
||||||
|
}
|
||||||
|
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
// nsId exists, update if different
|
// nsId exists, update if different
|
||||||
if (!current.contentEqualsTo(food)) {
|
if (!current.contentEqualsTo(food)) {
|
||||||
current.copyFrom(food)
|
current.copyFrom(food)
|
||||||
database.foodDao.updateExistingEntry(current)
|
database.foodDao.updateExistingEntry(current)
|
||||||
if (food.isValid && current.isValid) result.updated.add(current)
|
if (food.isValid && current.isValid) result.updated.add(current)
|
||||||
else if (!food.isValid && current.isValid) result.invalidated.add(current)
|
else if (!food.isValid && current.isValid) result.invalidated.add(current)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not known nsId, add
|
||||||
|
database.foodDao.insertNewEntry(food)
|
||||||
|
result.inserted.add(food)
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// not known nsId, add
|
|
||||||
database.foodDao.insertNewEntry(food)
|
|
||||||
result.inserted.add(food)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,10 @@ package info.nightscout.plugins.di
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import info.nightscout.plugins.general.food.FoodFragment
|
import info.nightscout.plugins.general.food.FoodFragment
|
||||||
import info.nightscout.plugins.general.food.FoodPlugin
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
abstract class FoodModule {
|
abstract class FoodModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesFoodFragment(): FoodFragment
|
@ContributesAndroidInjector abstract fun contributesFoodFragment(): FoodFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesFoodWorker(): FoodPlugin.FoodWorker
|
|
||||||
}
|
}
|
|
@ -1,25 +1,12 @@
|
||||||
package info.nightscout.plugins.general.food
|
package info.nightscout.plugins.general.food
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.work.WorkerParameters
|
|
||||||
import androidx.work.workDataOf
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.core.extensions.foodFromJson
|
|
||||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
|
||||||
import info.nightscout.core.utils.worker.LoggingWorker
|
|
||||||
import info.nightscout.database.entities.Food
|
|
||||||
import info.nightscout.database.impl.AppRepository
|
|
||||||
import info.nightscout.database.impl.transactions.SyncNsFoodTransaction
|
|
||||||
import info.nightscout.interfaces.plugin.PluginBase
|
import info.nightscout.interfaces.plugin.PluginBase
|
||||||
import info.nightscout.interfaces.plugin.PluginDescription
|
import info.nightscout.interfaces.plugin.PluginDescription
|
||||||
import info.nightscout.interfaces.plugin.PluginType
|
import info.nightscout.interfaces.plugin.PluginType
|
||||||
import info.nightscout.interfaces.utils.JsonHelper
|
|
||||||
import info.nightscout.plugins.R
|
import info.nightscout.plugins.R
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
|
||||||
import org.json.JSONObject
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -37,73 +24,4 @@ class FoodPlugin @Inject constructor(
|
||||||
.shortName(R.string.food_short)
|
.shortName(R.string.food_short)
|
||||||
.description(R.string.description_food),
|
.description(R.string.description_food),
|
||||||
aapsLogger, rh, injector
|
aapsLogger, rh, injector
|
||||||
) {
|
)
|
||||||
|
|
||||||
// cannot be inner class because of needed injection
|
|
||||||
class FoodWorker(
|
|
||||||
context: Context,
|
|
||||||
params: WorkerParameters
|
|
||||||
) : LoggingWorker(context, params) {
|
|
||||||
|
|
||||||
@Inject lateinit var injector: HasAndroidInjector
|
|
||||||
@Inject lateinit var repository: AppRepository
|
|
||||||
@Inject lateinit var sp: SP
|
|
||||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
|
||||||
|
|
||||||
override fun doWorkAndLog(): Result {
|
|
||||||
val foods = dataWorkerStorage.pickupJSONArray(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
|
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
|
||||||
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $foods")
|
|
||||||
|
|
||||||
var ret = Result.success()
|
|
||||||
|
|
||||||
for (index in 0 until foods.length()) {
|
|
||||||
val jsonFood: JSONObject = foods.getJSONObject(index)
|
|
||||||
|
|
||||||
if (JsonHelper.safeGetString(jsonFood, "type") != "food") continue
|
|
||||||
|
|
||||||
when (JsonHelper.safeGetString(jsonFood, "action")) {
|
|
||||||
"remove" -> {
|
|
||||||
val delFood = Food(
|
|
||||||
name = "",
|
|
||||||
portion = 0.0,
|
|
||||||
carbs = 0,
|
|
||||||
isValid = false
|
|
||||||
).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") }
|
|
||||||
|
|
||||||
repository.runTransactionForResult(SyncNsFoodTransaction(delFood))
|
|
||||||
.doOnError {
|
|
||||||
aapsLogger.error(LTag.DATABASE, "Error while removing food", it)
|
|
||||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
|
||||||
}
|
|
||||||
.blockingGet()
|
|
||||||
.also {
|
|
||||||
it.invalidated.forEach { f -> aapsLogger.debug(LTag.DATABASE, "Invalidated food ${f.interfaceIDs.nightscoutId}") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
val food = foodFromJson(jsonFood)
|
|
||||||
if (food != null) {
|
|
||||||
repository.runTransactionForResult(SyncNsFoodTransaction(food))
|
|
||||||
.doOnError {
|
|
||||||
aapsLogger.error(LTag.DATABASE, "Error while adding/updating food", it)
|
|
||||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
|
||||||
}
|
|
||||||
.blockingGet()
|
|
||||||
.also { result ->
|
|
||||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted food $it") }
|
|
||||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated food $it") }
|
|
||||||
result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated food $it") }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString())
|
|
||||||
ret = Result.failure(workDataOf("Error" to "Error parsing food"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,9 +20,11 @@ import info.nightscout.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWork
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
|
||||||
|
import info.nightscout.plugins.sync.nsclientV3.workers.LoadFoodsWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
|
||||||
|
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
|
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
|
||||||
import info.nightscout.plugins.sync.tidepool.TidepoolFragment
|
import info.nightscout.plugins.sync.tidepool.TidepoolFragment
|
||||||
|
|
||||||
|
@ -46,11 +48,14 @@ abstract class SyncModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesLoadStatusWorker(): LoadStatusWorker
|
@ContributesAndroidInjector abstract fun contributesLoadStatusWorker(): LoadStatusWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesLoadLastModificationWorker(): LoadLastModificationWorker
|
@ContributesAndroidInjector abstract fun contributesLoadLastModificationWorker(): LoadLastModificationWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesLoadBgWorker(): LoadBgWorker
|
@ContributesAndroidInjector abstract fun contributesLoadBgWorker(): LoadBgWorker
|
||||||
|
@ContributesAndroidInjector abstract fun contributesLoadFoodsWorker(): LoadFoodsWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesStoreBgWorker(): StoreDataForDbImpl.StoreBgWorker
|
@ContributesAndroidInjector abstract fun contributesStoreBgWorker(): StoreDataForDbImpl.StoreBgWorker
|
||||||
|
@ContributesAndroidInjector abstract fun contributesStoreFoodWorker(): StoreDataForDbImpl.StoreFoodWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker
|
@ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesProcessTreatmentsWorker(): ProcessTreatmentsWorker
|
@ContributesAndroidInjector abstract fun contributesProcessTreatmentsWorker(): ProcessTreatmentsWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker
|
@ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesDataSyncWorker(): DataSyncWorker
|
@ContributesAndroidInjector abstract fun contributesDataSyncWorker(): DataSyncWorker
|
||||||
|
@ContributesAndroidInjector abstract fun contributesFoodWorker(): ProcessFoodWorker
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import info.nightscout.database.impl.transactions.SyncNsBolusTransaction
|
||||||
import info.nightscout.database.impl.transactions.SyncNsCarbsTransaction
|
import info.nightscout.database.impl.transactions.SyncNsCarbsTransaction
|
||||||
import info.nightscout.database.impl.transactions.SyncNsEffectiveProfileSwitchTransaction
|
import info.nightscout.database.impl.transactions.SyncNsEffectiveProfileSwitchTransaction
|
||||||
import info.nightscout.database.impl.transactions.SyncNsExtendedBolusTransaction
|
import info.nightscout.database.impl.transactions.SyncNsExtendedBolusTransaction
|
||||||
|
import info.nightscout.database.impl.transactions.SyncNsFoodTransaction
|
||||||
import info.nightscout.database.impl.transactions.SyncNsOfflineEventTransaction
|
import info.nightscout.database.impl.transactions.SyncNsOfflineEventTransaction
|
||||||
import info.nightscout.database.impl.transactions.SyncNsProfileSwitchTransaction
|
import info.nightscout.database.impl.transactions.SyncNsProfileSwitchTransaction
|
||||||
import info.nightscout.database.impl.transactions.SyncNsTemporaryBasalTransaction
|
import info.nightscout.database.impl.transactions.SyncNsTemporaryBasalTransaction
|
||||||
|
@ -92,11 +93,11 @@ class StoreDataForDbImpl @Inject constructor(
|
||||||
override val temporaryBasals: MutableList<TemporaryBasal> = mutableListOf()
|
override val temporaryBasals: MutableList<TemporaryBasal> = mutableListOf()
|
||||||
override val profileSwitches: MutableList<ProfileSwitch> = mutableListOf()
|
override val profileSwitches: MutableList<ProfileSwitch> = mutableListOf()
|
||||||
override val offlineEvents: MutableList<OfflineEvent> = mutableListOf()
|
override val offlineEvents: MutableList<OfflineEvent> = mutableListOf()
|
||||||
|
override val foods: MutableList<Food> = mutableListOf()
|
||||||
|
|
||||||
override val nsIdGlucoseValues: MutableList<GlucoseValue> = mutableListOf()
|
override val nsIdGlucoseValues: MutableList<GlucoseValue> = mutableListOf()
|
||||||
override val nsIdBoluses: MutableList<Bolus> = mutableListOf()
|
override val nsIdBoluses: MutableList<Bolus> = mutableListOf()
|
||||||
override val nsIdCarbs: MutableList<Carbs> = mutableListOf()
|
override val nsIdCarbs: MutableList<Carbs> = mutableListOf()
|
||||||
override val nsIdFoods: MutableList<Food> = mutableListOf()
|
|
||||||
override val nsIdTemporaryTargets: MutableList<TemporaryTarget> = mutableListOf()
|
override val nsIdTemporaryTargets: MutableList<TemporaryTarget> = mutableListOf()
|
||||||
override val nsIdEffectiveProfileSwitches: MutableList<EffectiveProfileSwitch> = mutableListOf()
|
override val nsIdEffectiveProfileSwitches: MutableList<EffectiveProfileSwitch> = mutableListOf()
|
||||||
override val nsIdBolusCalculatorResults: MutableList<BolusCalculatorResult> = mutableListOf()
|
override val nsIdBolusCalculatorResults: MutableList<BolusCalculatorResult> = mutableListOf()
|
||||||
|
@ -106,6 +107,7 @@ class StoreDataForDbImpl @Inject constructor(
|
||||||
override val nsIdProfileSwitches: MutableList<ProfileSwitch> = mutableListOf()
|
override val nsIdProfileSwitches: MutableList<ProfileSwitch> = mutableListOf()
|
||||||
override val nsIdOfflineEvents: MutableList<OfflineEvent> = mutableListOf()
|
override val nsIdOfflineEvents: MutableList<OfflineEvent> = mutableListOf()
|
||||||
override val nsIdDeviceStatuses: MutableList<DeviceStatus> = mutableListOf()
|
override val nsIdDeviceStatuses: MutableList<DeviceStatus> = mutableListOf()
|
||||||
|
override val nsIdFoods: MutableList<Food> = mutableListOf()
|
||||||
|
|
||||||
private val userEntries: MutableList<UserEntry> = mutableListOf()
|
private val userEntries: MutableList<UserEntry> = mutableListOf()
|
||||||
|
|
||||||
|
@ -131,6 +133,19 @@ class StoreDataForDbImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StoreFoodWorker(
|
||||||
|
context: Context,
|
||||||
|
params: WorkerParameters
|
||||||
|
) : LoggingWorker(context, params) {
|
||||||
|
|
||||||
|
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||||
|
|
||||||
|
override fun doWorkAndLog(): Result {
|
||||||
|
storeDataForDb.storeFoodsToDb()
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> HashMap<T, Long>.inc(key: T) =
|
fun <T> HashMap<T, Long>.inc(key: T) =
|
||||||
if (containsKey(key)) merge(key, 1, Long::plus)
|
if (containsKey(key)) merge(key, 1, Long::plus)
|
||||||
else put(key, 1)
|
else put(key, 1)
|
||||||
|
@ -171,6 +186,36 @@ class StoreDataForDbImpl @Inject constructor(
|
||||||
rxBus.send(EventNSClientNewLog("DONE BG", ""))
|
rxBus.send(EventNSClientNewLog("DONE BG", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun storeFoodsToDb() {
|
||||||
|
rxBus.send(EventNSClientNewLog("PROCESSING FOOD", ""))
|
||||||
|
|
||||||
|
if (foods.isNotEmpty())
|
||||||
|
repository.runTransactionForResult(SyncNsFoodTransaction(foods))
|
||||||
|
.doOnError {
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Error while saving foods", it)
|
||||||
|
}
|
||||||
|
.blockingGet()
|
||||||
|
.also { result ->
|
||||||
|
foods.clear()
|
||||||
|
result.updated.forEach {
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Updated food $it")
|
||||||
|
updated.inc(Food::class.java.simpleName)
|
||||||
|
}
|
||||||
|
result.inserted.forEach {
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Inserted food $it")
|
||||||
|
inserted.inc(Food::class.java.simpleName)
|
||||||
|
}
|
||||||
|
result.invalidated.forEach {
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Invalidated food $it")
|
||||||
|
nsIdUpdated.inc(Food::class.java.simpleName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendLog("Food", Food::class.java.simpleName)
|
||||||
|
SystemClock.sleep(pause)
|
||||||
|
rxBus.send(EventNSClientNewLog("DONE FOOD", ""))
|
||||||
|
}
|
||||||
|
|
||||||
override fun storeTreatmentsToDb() {
|
override fun storeTreatmentsToDb() {
|
||||||
rxBus.send(EventNSClientNewLog("PROCESSING TR", ""))
|
rxBus.send(EventNSClientNewLog("PROCESSING TR", ""))
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ import info.nightscout.plugins.sync.nsclient.data.AlarmAck
|
||||||
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
|
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
|
||||||
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
|
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
|
||||||
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
|
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
|
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventAppExit
|
import info.nightscout.rx.events.EventAppExit
|
||||||
|
@ -522,11 +522,14 @@ class NSClientService : DaggerService() {
|
||||||
if (data.has("food")) {
|
if (data.has("food")) {
|
||||||
val foods = data.getJSONArray("food")
|
val foods = data.getJSONArray("food")
|
||||||
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods"))
|
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods"))
|
||||||
dataWorkerStorage.enqueue(
|
dataWorkerStorage
|
||||||
OneTimeWorkRequest.Builder(workerClasses.foodWorker)
|
.beginUniqueWork(
|
||||||
.setInputData(dataWorkerStorage.storeInputData(foods))
|
"ProcessFoods",
|
||||||
.build()
|
OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java)
|
||||||
)
|
.setInputData(dataWorkerStorage.storeInputData(foods))
|
||||||
|
.build()
|
||||||
|
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build())
|
||||||
|
.enqueue()
|
||||||
}
|
}
|
||||||
if (data.has("mbgs")) {
|
if (data.has("mbgs")) {
|
||||||
val mbgArray = data.getJSONArray("mbgs")
|
val mbgArray = data.getJSONArray("mbgs")
|
||||||
|
@ -550,7 +553,7 @@ class NSClientService : DaggerService() {
|
||||||
sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true)
|
sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true)
|
||||||
dataWorkerStorage
|
dataWorkerStorage
|
||||||
.beginUniqueWork(
|
.beginUniqueWork(
|
||||||
NSClientV3Plugin.JOB_NAME,
|
"ProcessBg",
|
||||||
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker)
|
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker)
|
||||||
.setInputData(dataWorkerStorage.storeInputData(sgvs))
|
.setInputData(dataWorkerStorage.storeInputData(sgvs))
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -38,6 +38,7 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolus
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolusWizard
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolusWizard
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSCarbs
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSCarbs
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSEffectiveProfileSwitch
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSEffectiveProfileSwitch
|
||||||
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSFood
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSProfileSwitch
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSProfileSwitch
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryBasal
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryBasal
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget
|
||||||
|
@ -293,6 +294,7 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
when (collection) {
|
when (collection) {
|
||||||
NsClient.Collection.ENTRIES -> lastLoadedSrvModified.collections.entries == 0L
|
NsClient.Collection.ENTRIES -> lastLoadedSrvModified.collections.entries == 0L
|
||||||
NsClient.Collection.TREATMENTS -> lastLoadedSrvModified.collections.treatments == 0L
|
NsClient.Collection.TREATMENTS -> lastLoadedSrvModified.collections.treatments == 0L
|
||||||
|
NsClient.Collection.FOODS -> lastLoadedSrvModified.collections.foods == 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateLatestBgReceivedIfNewer(latestReceived: Long) {
|
override fun updateLatestBgReceivedIfNewer(latestReceived: Long) {
|
||||||
|
@ -321,35 +323,76 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
|
|
||||||
private val gson: Gson = GsonBuilder().create()
|
private val gson: Gson = GsonBuilder().create()
|
||||||
private fun dbOperation(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) {
|
private fun dbOperation(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) {
|
||||||
val call = when (operation) {
|
if (collection == "food") {
|
||||||
Operation.CREATE -> nsAndroidClient?.let { return@let it::createTreatment }
|
val call = when (operation) {
|
||||||
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateTreatment }
|
Operation.CREATE -> nsAndroidClient?.let { return@let it::createFood }
|
||||||
}
|
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateFood }
|
||||||
when (dataPair) {
|
|
||||||
is DataSyncSelector.PairBolus -> dataPair.value.toNSBolus()
|
|
||||||
is DataSyncSelector.PairCarbs -> dataPair.value.toNSCarbs()
|
|
||||||
is DataSyncSelector.PairBolusCalculatorResult -> dataPair.value.toNSBolusWizard()
|
|
||||||
is DataSyncSelector.PairTemporaryTarget -> dataPair.value.toNSTemporaryTarget()
|
|
||||||
// is DataSyncSelector.PairFood -> dataPair.value.toJson(false)
|
|
||||||
// is DataSyncSelector.PairGlucoseValue -> dataPair.value.toJson(false, dateUtil)
|
|
||||||
is DataSyncSelector.PairTherapyEvent -> dataPair.value.toNSTherapyEvent()
|
|
||||||
|
|
||||||
is DataSyncSelector.PairTemporaryBasal -> {
|
|
||||||
val profile = profileFunction.getProfile(dataPair.value.timestamp)
|
|
||||||
if (profile == null) {
|
|
||||||
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dataPair.value.toNSTemporaryBasal(profile)
|
|
||||||
}
|
}
|
||||||
// is DataSyncSelector.PairExtendedBolus -> dataPair.value.toJson(false, profileFunction.getProfile(dataPair.value.timestamp), dateUtil)
|
when (dataPair) {
|
||||||
is DataSyncSelector.PairProfileSwitch -> dataPair.value.toNSProfileSwitch(dateUtil)
|
is DataSyncSelector.PairFood -> dataPair.value.toNSFood()
|
||||||
is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.toNSEffectiveProfileSwitch(dateUtil)
|
else -> null
|
||||||
// is DataSyncSelector.PairOfflineEvent -> dataPair.value.toJson(false, dateUtil)
|
}?.let { data ->
|
||||||
else -> null
|
runBlocking {
|
||||||
}?.let { data ->
|
try {
|
||||||
runBlocking {
|
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else ""
|
||||||
if (collection == "treatments") {
|
rxBus.send(
|
||||||
|
EventNSClientNewLog(
|
||||||
|
when (operation) {
|
||||||
|
Operation.CREATE -> "ADD $collection"
|
||||||
|
Operation.UPDATE -> "UPDATE $collection"
|
||||||
|
},
|
||||||
|
when (operation) {
|
||||||
|
Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress"
|
||||||
|
Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
call?.let { it(data) }?.let { result ->
|
||||||
|
when (dataPair) {
|
||||||
|
is DataSyncSelector.PairFood -> {
|
||||||
|
if (result.response == 201) { // created
|
||||||
|
dataPair.value.interfaceIDs.nightscoutId = result.identifier
|
||||||
|
storeDataForDb.nsIdFoods.add(dataPair.value)
|
||||||
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
|
}
|
||||||
|
dataSyncSelector.confirmLastFoodIdIfGreater(dataPair.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (collection == "treatments") {
|
||||||
|
val call = when (operation) {
|
||||||
|
Operation.CREATE -> nsAndroidClient?.let { return@let it::createTreatment }
|
||||||
|
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateTreatment }
|
||||||
|
}
|
||||||
|
when (dataPair) {
|
||||||
|
is DataSyncSelector.PairBolus -> dataPair.value.toNSBolus()
|
||||||
|
is DataSyncSelector.PairCarbs -> dataPair.value.toNSCarbs()
|
||||||
|
is DataSyncSelector.PairBolusCalculatorResult -> dataPair.value.toNSBolusWizard()
|
||||||
|
is DataSyncSelector.PairTemporaryTarget -> dataPair.value.toNSTemporaryTarget()
|
||||||
|
// is DataSyncSelector.PairGlucoseValue -> dataPair.value.toJson(false, dateUtil)
|
||||||
|
is DataSyncSelector.PairTherapyEvent -> dataPair.value.toNSTherapyEvent()
|
||||||
|
|
||||||
|
is DataSyncSelector.PairTemporaryBasal -> {
|
||||||
|
val profile = profileFunction.getProfile(dataPair.value.timestamp)
|
||||||
|
if (profile == null) {
|
||||||
|
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataPair.value.toNSTemporaryBasal(profile)
|
||||||
|
}
|
||||||
|
// is DataSyncSelector.PairExtendedBolus -> dataPair.value.toJson(false, profileFunction.getProfile(dataPair.value.timestamp), dateUtil)
|
||||||
|
is DataSyncSelector.PairProfileSwitch -> dataPair.value.toNSProfileSwitch(dateUtil)
|
||||||
|
is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.toNSEffectiveProfileSwitch(dateUtil)
|
||||||
|
// is DataSyncSelector.PairOfflineEvent -> dataPair.value.toJson(false, dateUtil)
|
||||||
|
else -> null
|
||||||
|
}?.let { data ->
|
||||||
|
runBlocking {
|
||||||
try {
|
try {
|
||||||
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else ""
|
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else ""
|
||||||
rxBus.send(
|
rxBus.send(
|
||||||
|
@ -401,7 +444,6 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
}
|
}
|
||||||
dataSyncSelector.confirmLastTempTargetsIdIfGreater(dataPair.id)
|
dataSyncSelector.confirmLastTempTargetsIdIfGreater(dataPair.id)
|
||||||
}
|
}
|
||||||
// is DataSyncSelector.PairFood -> dataPair.value.toJson(false)
|
|
||||||
// is DataSyncSelector.PairGlucoseValue -> dataPair.value.toJson(false, dateUtil)
|
// is DataSyncSelector.PairGlucoseValue -> dataPair.value.toJson(false, dateUtil)
|
||||||
is DataSyncSelector.PairTherapyEvent -> {
|
is DataSyncSelector.PairTherapyEvent -> {
|
||||||
if (result.response == 201) { // created
|
if (result.response == 201) { // created
|
||||||
|
@ -487,6 +529,7 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
.then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build())
|
.then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build())
|
||||||
// Other Workers are enqueued after BG finish
|
// Other Workers are enqueued after BG finish
|
||||||
// LoadTreatmentsWorker
|
// LoadTreatmentsWorker
|
||||||
|
// LoadFoodsWorker
|
||||||
// LoadDeviceStatusWorker
|
// LoadDeviceStatusWorker
|
||||||
// DataSyncWorker
|
// DataSyncWorker
|
||||||
.enqueue()
|
.enqueue()
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package info.nightscout.plugins.sync.nsclientV3.extensions
|
||||||
|
|
||||||
|
import info.nightscout.database.entities.Food
|
||||||
|
import info.nightscout.database.entities.embedments.InterfaceIDs
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
|
|
||||||
|
fun NSFood.toFood(): Food =
|
||||||
|
Food(
|
||||||
|
isValid = isValid,
|
||||||
|
name = name,
|
||||||
|
category = category,
|
||||||
|
subCategory = subCategory,
|
||||||
|
portion = portion,
|
||||||
|
carbs = carbs,
|
||||||
|
fat = fat,
|
||||||
|
protein = protein,
|
||||||
|
energy = energy,
|
||||||
|
unit = unit,
|
||||||
|
gi = gi,
|
||||||
|
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Food.toNSFood(): NSFood =
|
||||||
|
NSFood(
|
||||||
|
date = System.currentTimeMillis(),
|
||||||
|
isValid = isValid,
|
||||||
|
name = name,
|
||||||
|
category = category,
|
||||||
|
subCategory = subCategory,
|
||||||
|
portion = portion,
|
||||||
|
carbs = carbs,
|
||||||
|
fat = fat,
|
||||||
|
protein = protein,
|
||||||
|
energy = energy,
|
||||||
|
unit = unit,
|
||||||
|
gi = gi,
|
||||||
|
identifier = interfaceIDs.nightscoutId,
|
||||||
|
)
|
|
@ -0,0 +1,68 @@
|
||||||
|
package info.nightscout.plugins.sync.nsclientV3.workers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import androidx.work.workDataOf
|
||||||
|
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||||
|
import info.nightscout.core.utils.worker.LoggingWorker
|
||||||
|
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||||
|
import info.nightscout.interfaces.workflow.WorkerClasses
|
||||||
|
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
|
||||||
|
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
|
||||||
|
import info.nightscout.rx.bus.RxBus
|
||||||
|
import info.nightscout.rx.events.EventNSClientNewLog
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
|
import info.nightscout.shared.utils.DateUtil
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LoadFoodsWorker(
|
||||||
|
context: Context,
|
||||||
|
params: WorkerParameters
|
||||||
|
) : LoggingWorker(context, params) {
|
||||||
|
|
||||||
|
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||||
|
@Inject lateinit var rxBus: RxBus
|
||||||
|
@Inject lateinit var context: Context
|
||||||
|
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||||
|
@Inject lateinit var workerClasses: WorkerClasses
|
||||||
|
|
||||||
|
override fun doWorkAndLog(): Result {
|
||||||
|
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
|
||||||
|
|
||||||
|
// Food database doesn't provide last record modification
|
||||||
|
// Read full collection every 5th attempt
|
||||||
|
runBlocking {
|
||||||
|
if (nsClientV3Plugin.lastLoadedSrvModified.collections.foods++ % 5 == 0L) {
|
||||||
|
val foods: List<NSFood> = nsAndroidClient.getFoods(1000)
|
||||||
|
aapsLogger.debug("FOODS: $foods")
|
||||||
|
rxBus.send(EventNSClientNewLog("RCV", "${foods.size} FOODs"))
|
||||||
|
// Schedule processing of fetched data
|
||||||
|
WorkManager.getInstance(context)
|
||||||
|
.beginUniqueWork(
|
||||||
|
NSClientV3Plugin.JOB_NAME,
|
||||||
|
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
||||||
|
OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java)
|
||||||
|
.setInputData(dataWorkerStorage.storeInputData(foods))
|
||||||
|
.build()
|
||||||
|
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build())
|
||||||
|
.then(OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build())
|
||||||
|
.enqueue()
|
||||||
|
} else {
|
||||||
|
rxBus.send(EventNSClientNewLog("RCV", "FOOD skipped"))
|
||||||
|
WorkManager.getInstance(context)
|
||||||
|
.enqueueUniqueWork(
|
||||||
|
NSClientV3Plugin.JOB_NAME,
|
||||||
|
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
||||||
|
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,7 +46,8 @@ class LoadTreatmentsWorker(
|
||||||
val treatments: List<NSTreatment>
|
val treatments: List<NSTreatment>
|
||||||
val response: NSAndroidClient.ReadResponse<List<NSTreatment>>?
|
val response: NSAndroidClient.ReadResponse<List<NSTreatment>>?
|
||||||
if (isFirstLoad) {
|
if (isFirstLoad) {
|
||||||
treatments = nsAndroidClient.getTreatmentsNewerThan(lastLoaded, 500)
|
val lastLoadedIso = dateUtil.toISOString(lastLoaded)
|
||||||
|
treatments = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, 500)
|
||||||
response = NSAndroidClient.ReadResponse(0, treatments)
|
response = NSAndroidClient.ReadResponse(0, treatments)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -75,14 +76,13 @@ class LoadTreatmentsWorker(
|
||||||
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
|
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
|
||||||
nsClientV3Plugin.storeLastFetched()
|
nsClientV3Plugin.storeLastFetched()
|
||||||
}
|
}
|
||||||
rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil
|
rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
|
||||||
.dateAndTimeAndSecondsString(lastLoaded)}"))
|
|
||||||
storeDataForDb.storeTreatmentsToDb()
|
storeDataForDb.storeTreatmentsToDb()
|
||||||
WorkManager.getInstance(context)
|
WorkManager.getInstance(context)
|
||||||
.enqueueUniqueWork(
|
.enqueueUniqueWork(
|
||||||
NSClientV3Plugin.JOB_NAME,
|
NSClientV3Plugin.JOB_NAME,
|
||||||
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
||||||
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
|
OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (error: Exception) {
|
} catch (error: Exception) {
|
||||||
|
@ -95,14 +95,13 @@ class LoadTreatmentsWorker(
|
||||||
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
|
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
|
||||||
nsClientV3Plugin.storeLastFetched()
|
nsClientV3Plugin.storeLastFetched()
|
||||||
}
|
}
|
||||||
rxBus.send(EventNSClientNewLog("RCV END", "No new TRs from ${dateUtil
|
rxBus.send(EventNSClientNewLog("RCV END", "No new TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
|
||||||
.dateAndTimeAndSecondsString(lastLoaded)}"))
|
|
||||||
storeDataForDb.storeTreatmentsToDb()
|
storeDataForDb.storeTreatmentsToDb()
|
||||||
WorkManager.getInstance(context)
|
WorkManager.getInstance(context)
|
||||||
.enqueueUniqueWork(
|
.enqueueUniqueWork(
|
||||||
NSClientV3Plugin.JOB_NAME,
|
NSClientV3Plugin.JOB_NAME,
|
||||||
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
ExistingWorkPolicy.APPEND_OR_REPLACE,
|
||||||
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
|
OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package info.nightscout.plugins.sync.nsclientV3.workers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import androidx.work.workDataOf
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.core.extensions.foodFromJson
|
||||||
|
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||||
|
import info.nightscout.core.utils.worker.LoggingWorker
|
||||||
|
import info.nightscout.database.entities.Food
|
||||||
|
import info.nightscout.database.impl.AppRepository
|
||||||
|
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||||
|
import info.nightscout.interfaces.utils.JsonHelper
|
||||||
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toFood
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ProcessFoodWorker(
|
||||||
|
context: Context,
|
||||||
|
params: WorkerParameters
|
||||||
|
) : LoggingWorker(context, params) {
|
||||||
|
|
||||||
|
@Inject lateinit var injector: HasAndroidInjector
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||||
|
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||||
|
|
||||||
|
override fun doWorkAndLog(): Result {
|
||||||
|
val data = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
|
||||||
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $data")
|
||||||
|
|
||||||
|
val ret = Result.success()
|
||||||
|
val foods = mutableListOf<Food>()
|
||||||
|
|
||||||
|
if (data is JSONArray) {
|
||||||
|
for (index in 0 until data.length()) {
|
||||||
|
val jsonFood: JSONObject = data.getJSONObject(index)
|
||||||
|
|
||||||
|
if (JsonHelper.safeGetString(jsonFood, "type") != "food") continue
|
||||||
|
|
||||||
|
when (JsonHelper.safeGetString(jsonFood, "action")) {
|
||||||
|
"remove" -> {
|
||||||
|
val delFood = Food(
|
||||||
|
name = "",
|
||||||
|
portion = 0.0,
|
||||||
|
carbs = 0,
|
||||||
|
isValid = false
|
||||||
|
).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") }
|
||||||
|
foods += delFood
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val food = foodFromJson(jsonFood)
|
||||||
|
if (food != null) foods += food
|
||||||
|
else aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (data is List<*>) {
|
||||||
|
for (i in 0 until data.size)
|
||||||
|
foods += (data[i] as NSFood).toFood()
|
||||||
|
}
|
||||||
|
storeDataForDb.foods.addAll(foods)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package info.nightscout.plugins.sync.nsclientV3.extensions
|
||||||
|
|
||||||
|
import info.nightscout.database.entities.Food
|
||||||
|
import info.nightscout.database.entities.embedments.InterfaceIDs
|
||||||
|
import info.nightscout.sdk.localmodel.food.NSFood
|
||||||
|
import info.nightscout.sdk.mapper.convertToRemoteAndBack
|
||||||
|
import org.junit.jupiter.api.Assertions
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
internal class FoodExtensionKtTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toFood() {
|
||||||
|
val food = Food(
|
||||||
|
isValid = true,
|
||||||
|
name = "name",
|
||||||
|
category = "category",
|
||||||
|
subCategory = "subcategory",
|
||||||
|
portion = 2.0,
|
||||||
|
carbs = 20,
|
||||||
|
fat = 21,
|
||||||
|
protein = 22,
|
||||||
|
energy = 23,
|
||||||
|
unit = "g",
|
||||||
|
gi = 25,
|
||||||
|
interfaceIDs_backing = InterfaceIDs(
|
||||||
|
nightscoutId = "nightscoutId"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val food2 = (food.toNSFood().convertToRemoteAndBack() as NSFood).toFood()
|
||||||
|
Assertions.assertTrue(food.contentEqualsTo(food2))
|
||||||
|
Assertions.assertTrue(food.interfaceIdsEqualsTo(food2))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue