food -> Room
This commit is contained in:
parent
3d4d27439a
commit
a2fbab02f9
34 changed files with 3437 additions and 643 deletions
|
@ -109,6 +109,7 @@ class MainApp : DaggerApplication() {
|
||||||
filter.addAction(Intents.ACTION_NEW_PROFILE)
|
filter.addAction(Intents.ACTION_NEW_PROFILE)
|
||||||
filter.addAction(Intents.ACTION_NEW_MBG)
|
filter.addAction(Intents.ACTION_NEW_MBG)
|
||||||
filter.addAction(Intents.ACTION_NEW_CAL)
|
filter.addAction(Intents.ACTION_NEW_CAL)
|
||||||
|
filter.addAction(Intents.ACTION_FOOD)
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(DataReceiver(), filter)
|
LocalBroadcastManager.getInstance(this).registerReceiver(DataReceiver(), filter)
|
||||||
filter = IntentFilter()
|
filter = IntentFilter()
|
||||||
filter.addAction(Intent.ACTION_TIME_CHANGED)
|
filter.addAction(Intent.ACTION_TIME_CHANGED)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package info.nightscout.androidaps.db
|
package info.nightscout.androidaps.db
|
||||||
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||||
|
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
||||||
import info.nightscout.androidaps.events.EventNewBG
|
import info.nightscout.androidaps.events.EventNewBG
|
||||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||||
import info.nightscout.androidaps.events.EventTherapyEventChange
|
import info.nightscout.androidaps.events.EventTherapyEventChange
|
||||||
|
@ -44,5 +46,9 @@ class CompatDBHelper @Inject constructor(
|
||||||
aapsLogger.debug(LTag.DATABASE, "Firing EventTherapyEventChange")
|
aapsLogger.debug(LTag.DATABASE, "Firing EventTherapyEventChange")
|
||||||
rxBus.send(EventTherapyEventChange())
|
rxBus.send(EventTherapyEventChange())
|
||||||
}
|
}
|
||||||
|
it.filterIsInstance<Food>().firstOrNull()?.let {
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged")
|
||||||
|
rxBus.send(EventFoodDatabaseChanged())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.dependencyInjection
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import info.nightscout.androidaps.db.DatabaseHelper
|
import info.nightscout.androidaps.db.DatabaseHelper
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodService
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentService
|
import info.nightscout.androidaps.plugins.treatments.TreatmentService
|
||||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||||
|
@ -17,7 +16,6 @@ abstract class DataClassesModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun DatabaseHelperInjector(): DatabaseHelper
|
@ContributesAndroidInjector abstract fun DatabaseHelperInjector(): DatabaseHelper
|
||||||
@ContributesAndroidInjector abstract fun treatmentServiceInjector(): TreatmentService
|
@ContributesAndroidInjector abstract fun treatmentServiceInjector(): TreatmentService
|
||||||
@ContributesAndroidInjector abstract fun foodServiceInjector(): FoodService
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun bolusWizardInjector(): BolusWizard
|
@ContributesAndroidInjector abstract fun bolusWizardInjector(): BolusWizard
|
||||||
@ContributesAndroidInjector abstract fun quickWizardEntryInjector(): QuickWizardEntry
|
@ContributesAndroidInjector abstract fun quickWizardEntryInjector(): QuickWizardEntry
|
||||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.dependencyInjection
|
||||||
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
|
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||||
|
@ -22,4 +23,5 @@ abstract class WorkersModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker
|
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker
|
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientWorker
|
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientWorker
|
||||||
|
@ContributesAndroidInjector abstract fun contributesFoodWorker(): FoodPlugin.FoodWorker
|
||||||
}
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
package info.nightscout.androidaps.events
|
|
||||||
|
|
||||||
import org.json.JSONArray
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event which is published with data fetched from NightScout specific for the
|
|
||||||
* Food-class.
|
|
||||||
*
|
|
||||||
* Payload is the from NS retrieved JSON-String which should be handled by all
|
|
||||||
* subscriber.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class EventNsFood(val mode: Int, val foods: JSONArray) : Event() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val ADD = 0
|
|
||||||
val UPDATE = 1
|
|
||||||
val REMOVE = 2
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.food;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.j256.ormlite.field.DatabaseField;
|
|
||||||
import com.j256.ormlite.table.DatabaseTable;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.utils.JsonHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mike on 20.09.2017.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@DatabaseTable(tableName = Food.TABLE_FOODS)
|
|
||||||
public class Food {
|
|
||||||
static final String TABLE_FOODS = "Foods";
|
|
||||||
|
|
||||||
@DatabaseField(id = true)
|
|
||||||
public long key;
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public boolean isValid = true;
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public String _id; // NS _id
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public String name;
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public String category;
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public String subcategory;
|
|
||||||
|
|
||||||
// Example:
|
|
||||||
// name="juice" portion=250 units="ml" carbs=12
|
|
||||||
// means 250ml of juice has 12g of carbs
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public double portion; // common portion in "units"
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public int carbs; // in grams
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public int fat = 0; // in grams
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public int protein = 0; // in grams
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public int energy = 0; // in kJ
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public String units = "g";
|
|
||||||
|
|
||||||
@DatabaseField
|
|
||||||
public int gi; // not used yet
|
|
||||||
|
|
||||||
private Food() {
|
|
||||||
key = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Food createFromJson(JSONObject json) throws JSONException {
|
|
||||||
Food food = new Food();
|
|
||||||
if ("food".equals(JsonHelper.safeGetString(json, "type"))) {
|
|
||||||
food._id = JsonHelper.safeGetString(json, "_id");
|
|
||||||
food.category = JsonHelper.safeGetString(json, "category");
|
|
||||||
food.subcategory = JsonHelper.safeGetString(json, "subcategory");
|
|
||||||
food.name = JsonHelper.safeGetString(json, "name");
|
|
||||||
food.units = JsonHelper.safeGetString(json, "unit");
|
|
||||||
food.portion = JsonHelper.safeGetDouble(json, "portion");
|
|
||||||
food.carbs = JsonHelper.safeGetInt(json, "carbs");
|
|
||||||
food.gi = JsonHelper.safeGetInt(json, "gi");
|
|
||||||
food.energy = JsonHelper.safeGetInt(json, "energy");
|
|
||||||
food.protein = JsonHelper.safeGetInt(json, "protein");
|
|
||||||
food.fat = JsonHelper.safeGetInt(json, "fat");
|
|
||||||
}
|
|
||||||
|
|
||||||
return food;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEqual(Food other) {
|
|
||||||
if (portion != other.portion)
|
|
||||||
return false;
|
|
||||||
if (carbs != other.carbs)
|
|
||||||
return false;
|
|
||||||
if (fat != other.fat)
|
|
||||||
return false;
|
|
||||||
if (protein != other.protein)
|
|
||||||
return false;
|
|
||||||
if (energy != other.energy)
|
|
||||||
return false;
|
|
||||||
if (gi != other.gi)
|
|
||||||
return false;
|
|
||||||
if (!Objects.equals(_id, other._id))
|
|
||||||
return false;
|
|
||||||
if (!Objects.equals(name, other.name))
|
|
||||||
return false;
|
|
||||||
if (!Objects.equals(category, other.category))
|
|
||||||
return false;
|
|
||||||
if (!Objects.equals(subcategory, other.subcategory))
|
|
||||||
return false;
|
|
||||||
return Objects.equals(units, other.units);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyFrom(Food other) {
|
|
||||||
isValid = other.isValid;
|
|
||||||
_id = other._id;
|
|
||||||
name = other.name;
|
|
||||||
category = other.category;
|
|
||||||
subcategory = other.subcategory;
|
|
||||||
portion = other.portion;
|
|
||||||
carbs = other.carbs;
|
|
||||||
fat = other.fat;
|
|
||||||
protein = other.protein;
|
|
||||||
energy = other.energy;
|
|
||||||
units = other.units;
|
|
||||||
gi = other.gi;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override @NonNull
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("_id=" + _id + ";");
|
|
||||||
sb.append("isValid=" + isValid + ";");
|
|
||||||
sb.append("name=" + name + ";");
|
|
||||||
sb.append("category=" + category + ";");
|
|
||||||
sb.append("subcategory=" + subcategory + ";");
|
|
||||||
sb.append("portion=" + portion + ";");
|
|
||||||
sb.append("carbs=" + carbs + ";");
|
|
||||||
sb.append("protein=" + protein + ";");
|
|
||||||
sb.append("energy=" + energy + ";");
|
|
||||||
sb.append("units=" + units + ";");
|
|
||||||
sb.append("gi=" + gi + ";");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.general.food
|
package info.nightscout.androidaps.plugins.general.food
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
|
@ -15,20 +14,30 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.*
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
|
import info.nightscout.androidaps.database.transactions.InvalidateFoodTransaction
|
||||||
import info.nightscout.androidaps.databinding.FoodFragmentBinding
|
import info.nightscout.androidaps.databinding.FoodFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.FoodItemBinding
|
import info.nightscout.androidaps.databinding.FoodItemBinding
|
||||||
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import io.reactivex.Completable
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
@ -36,10 +45,11 @@ class FoodFragment : DaggerFragment() {
|
||||||
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var foodPlugin: FoodPlugin
|
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
@Inject lateinit var nsUpload: NSUpload
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
@ -62,8 +72,23 @@ class FoodFragment : DaggerFragment() {
|
||||||
|
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
binding.recyclerview.adapter = RecyclerViewAdapter(foodPlugin.service?.foodData
|
|
||||||
?: ArrayList())
|
binding.refreshFromNightscout.setOnClickListener {
|
||||||
|
context?.let { context ->
|
||||||
|
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", {
|
||||||
|
uel.log(Action.FOOD_FROM_NS)
|
||||||
|
disposable += Completable.fromAction { repository.deleteAllFoods() }
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
|
.observeOn(aapsSchedulers.main)
|
||||||
|
.subscribeBy(
|
||||||
|
onError = { aapsLogger.error("Error removing foods", it) },
|
||||||
|
onComplete = { rxBus.send(EventFoodDatabaseChanged()) }
|
||||||
|
)
|
||||||
|
|
||||||
|
rxBus.send(EventNSClientRestart())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.clearfilter.setOnClickListener {
|
binding.clearfilter.setOnClickListener {
|
||||||
binding.filter.setText("")
|
binding.filter.setText("")
|
||||||
|
@ -99,10 +124,6 @@ class FoodFragment : DaggerFragment() {
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable) {}
|
override fun afterTextChanged(s: Editable) {}
|
||||||
})
|
})
|
||||||
loadData()
|
|
||||||
fillCategories()
|
|
||||||
fillSubcategories()
|
|
||||||
filterData()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -111,9 +132,23 @@ class FoodFragment : DaggerFragment() {
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
.toObservable(EventFoodDatabaseChanged::class.java)
|
.toObservable(EventFoodDatabaseChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
.debounce(1L, TimeUnit.SECONDS)
|
||||||
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
)
|
)
|
||||||
updateGui()
|
swapAdapter()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun swapAdapter() {
|
||||||
|
disposable += repository
|
||||||
|
.getFoodData()
|
||||||
|
.observeOn(aapsSchedulers.main)
|
||||||
|
.subscribe { list ->
|
||||||
|
unfiltered = list
|
||||||
|
fillCategories()
|
||||||
|
fillSubcategories()
|
||||||
|
filterData()
|
||||||
|
binding.recyclerview.swapAdapter(RecyclerViewAdapter(filtered), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -128,14 +163,11 @@ class FoodFragment : DaggerFragment() {
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
|
||||||
unfiltered = foodPlugin.service?.foodData ?: ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fillCategories() {
|
private fun fillCategories() {
|
||||||
val catSet: MutableSet<CharSequence> = HashSet()
|
val catSet: MutableSet<CharSequence> = HashSet()
|
||||||
for (f in unfiltered) {
|
for (f in unfiltered) {
|
||||||
if (f.category != null && f.category != "") catSet.add(f.category)
|
val category = f.category
|
||||||
|
if (!category.isNullOrBlank()) catSet.add(category)
|
||||||
}
|
}
|
||||||
// make it unique
|
// make it unique
|
||||||
val categories = ArrayList(catSet)
|
val categories = ArrayList(catSet)
|
||||||
|
@ -151,7 +183,10 @@ class FoodFragment : DaggerFragment() {
|
||||||
val subCatSet: MutableSet<CharSequence> = HashSet()
|
val subCatSet: MutableSet<CharSequence> = HashSet()
|
||||||
if (categoryFilter != resourceHelper.gs(R.string.none)) {
|
if (categoryFilter != resourceHelper.gs(R.string.none)) {
|
||||||
for (f in unfiltered) {
|
for (f in unfiltered) {
|
||||||
if (f.category != null && f.category == categoryFilter) if (f.subcategory != null && f.subcategory != "") subCatSet.add(f.subcategory)
|
if (f.category != null && f.category == categoryFilter) {
|
||||||
|
val subCategory = f.subCategory
|
||||||
|
if (!subCategory.isNullOrEmpty()) subCatSet.add(subCategory)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// make it unique
|
// make it unique
|
||||||
|
@ -169,21 +204,19 @@ class FoodFragment : DaggerFragment() {
|
||||||
val subcategoryFilter = binding.subcategory.selectedItem.toString()
|
val subcategoryFilter = binding.subcategory.selectedItem.toString()
|
||||||
val newFiltered = ArrayList<Food>()
|
val newFiltered = ArrayList<Food>()
|
||||||
for (f in unfiltered) {
|
for (f in unfiltered) {
|
||||||
if (f.name == null || f.category == null || f.subcategory == null) continue
|
if (f.category == null || f.subCategory == null) continue
|
||||||
if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subcategory != subcategoryFilter) continue
|
if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subCategory != subcategoryFilter) continue
|
||||||
if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) continue
|
if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) continue
|
||||||
if (textFilter != "" && !f.name.toLowerCase(Locale.getDefault()).contains(textFilter.toLowerCase(Locale.getDefault()))) continue
|
if (textFilter != "" && !f.name.toLowerCase(Locale.getDefault()).contains(textFilter.toLowerCase(Locale.getDefault()))) continue
|
||||||
newFiltered.add(f)
|
newFiltered.add(f)
|
||||||
}
|
}
|
||||||
filtered = newFiltered
|
filtered = newFiltered
|
||||||
updateGui()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateGui() {
|
|
||||||
binding.recyclerview.swapAdapter(RecyclerViewAdapter(filtered), true)
|
binding.recyclerview.swapAdapter(RecyclerViewAdapter(filtered), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RecyclerViewAdapter internal constructor(var foodList: List<Food>) : RecyclerView.Adapter<FoodsViewHolder>() {
|
fun Int?.isNotZero(): Boolean = this != null && this != 0
|
||||||
|
|
||||||
|
inner class RecyclerViewAdapter internal constructor(private var foodList: List<Food>) : RecyclerView.Adapter<RecyclerViewAdapter.FoodsViewHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoodsViewHolder {
|
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoodsViewHolder {
|
||||||
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.food_item, viewGroup, false)
|
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.food_item, viewGroup, false)
|
||||||
|
@ -193,16 +226,16 @@ class FoodFragment : DaggerFragment() {
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onBindViewHolder(holder: FoodsViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: FoodsViewHolder, position: Int) {
|
||||||
val food = foodList[position]
|
val food = foodList[position]
|
||||||
holder.binding.nsSign.visibility = if (food._id != null) View.VISIBLE else View.GONE
|
holder.binding.nsSign.visibility = (food.interfaceIDs.nightscoutId != null).toVisibility()
|
||||||
holder.binding.name.text = food.name
|
holder.binding.name.text = food.name
|
||||||
holder.binding.portion.text = food.portion.toString() + food.units
|
holder.binding.portion.text = food.portion.toString() + food.unit
|
||||||
holder.binding.carbs.text = food.carbs.toString() + resourceHelper.gs(R.string.shortgramm)
|
holder.binding.carbs.text = food.carbs.toString() + resourceHelper.gs(R.string.shortgramm)
|
||||||
holder.binding.fat.text = resourceHelper.gs(R.string.shortfat) + ": " + food.fat + resourceHelper.gs(R.string.shortgramm)
|
holder.binding.fat.text = resourceHelper.gs(R.string.shortfat) + ": " + food.fat + resourceHelper.gs(R.string.shortgramm)
|
||||||
if (food.fat == 0) holder.binding.fat.visibility = View.INVISIBLE
|
holder.binding.fat.visibility = food.fat.isNotZero().toVisibility()
|
||||||
holder.binding.protein.text = resourceHelper.gs(R.string.shortprotein) + ": " + food.protein + resourceHelper.gs(R.string.shortgramm)
|
holder.binding.protein.text = resourceHelper.gs(R.string.shortprotein) + ": " + food.protein + resourceHelper.gs(R.string.shortgramm)
|
||||||
if (food.protein == 0) holder.binding.protein.visibility = View.INVISIBLE
|
holder.binding.protein.visibility = food.protein.isNotZero().toVisibility()
|
||||||
holder.binding.energy.text = resourceHelper.gs(R.string.shortenergy) + ": " + food.energy + resourceHelper.gs(R.string.shortkilojoul)
|
holder.binding.energy.text = resourceHelper.gs(R.string.shortenergy) + ": " + food.energy + resourceHelper.gs(R.string.shortkilojoul)
|
||||||
if (food.energy == 0) holder.binding.energy.visibility = View.INVISIBLE
|
holder.binding.energy.visibility = food.energy.isNotZero().toVisibility()
|
||||||
holder.binding.remove.tag = food
|
holder.binding.remove.tag = food
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,12 +249,17 @@ class FoodFragment : DaggerFragment() {
|
||||||
binding.remove.setOnClickListener { v: View ->
|
binding.remove.setOnClickListener { v: View ->
|
||||||
val food = v.tag as Food
|
val food = v.tag as Food
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + "\n" + food.name, {
|
||||||
uel.log(Action.FOOD_REMOVED, food.name)
|
uel.log(Action.FOOD_REMOVED, food.name)
|
||||||
if (food._id != null && food._id != "") {
|
disposable += repository.runTransactionForResult(InvalidateFoodTransaction(food.id))
|
||||||
nsUpload.removeFoodFromNS(food._id)
|
.subscribe({
|
||||||
}
|
val id = food.interfaceIDs.nightscoutId
|
||||||
foodPlugin.service?.delete(food)
|
if (NSUpload.isIdValid(id)) nsUpload.removeFoodFromNS(id)
|
||||||
|
// no create at the moment
|
||||||
|
// else uploadQueue.removeID("dbAdd", food.timestamp.toString())
|
||||||
|
}, {
|
||||||
|
aapsLogger.error(LTag.BGSOURCE, "Error while invalidating food", it)
|
||||||
|
})
|
||||||
}, null)
|
}, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,28 @@
|
||||||
package info.nightscout.androidaps.plugins.general.food
|
package info.nightscout.androidaps.plugins.general.food
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
import info.nightscout.androidaps.database.transactions.SyncFoodTransaction
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.receivers.BundleStore
|
||||||
|
import info.nightscout.androidaps.receivers.DataReceiver
|
||||||
|
import info.nightscout.androidaps.utils.JsonHelper
|
||||||
|
import info.nightscout.androidaps.utils.extensions.foodFromJson
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -25,10 +41,75 @@ class FoodPlugin @Inject constructor(
|
||||||
aapsLogger, resourceHelper, injector
|
aapsLogger, resourceHelper, injector
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var service: FoodService? = null
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
override fun onStart() {
|
// cannot be inner class because of needed injection
|
||||||
super.onStart()
|
class FoodWorker(
|
||||||
service = FoodService(injector)
|
context: Context,
|
||||||
|
params: WorkerParameters
|
||||||
|
) : Worker(context, params) {
|
||||||
|
|
||||||
|
@Inject lateinit var injector: HasAndroidInjector
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var bundleStore: BundleStore
|
||||||
|
@Inject lateinit var foodPlugin: FoodPlugin
|
||||||
|
|
||||||
|
init {
|
||||||
|
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
aapsLogger.debug(LTag.DATAFOOD, "Received Food Data: $inputData}")
|
||||||
|
val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1))
|
||||||
|
?: return Result.failure()
|
||||||
|
|
||||||
|
var ret = Result.success()
|
||||||
|
|
||||||
|
val foodsString = bundle.getString("foods") ?: return Result.failure()
|
||||||
|
val foods = JSONArray(foodsString)
|
||||||
|
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") }
|
||||||
|
|
||||||
|
foodPlugin.disposable += repository.runTransactionForResult(SyncFoodTransaction(delFood)).subscribe({ result ->
|
||||||
|
result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food ${it.interfaceIDs.nightscoutId}") }
|
||||||
|
}, {
|
||||||
|
aapsLogger.error(LTag.DATAFOOD, "Error while removing food", it)
|
||||||
|
ret = Result.failure()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val food = foodFromJson(jsonFood)
|
||||||
|
if (food != null) {
|
||||||
|
foodPlugin.disposable += repository.runTransactionForResult(SyncFoodTransaction(food)).subscribe({ result ->
|
||||||
|
result.inserted.forEach { aapsLogger.debug(LTag.DATAFOOD, "Inserted food $it") }
|
||||||
|
result.updated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Updated food $it") }
|
||||||
|
result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food $it") }
|
||||||
|
}, {
|
||||||
|
aapsLogger.error(LTag.DATAFOOD, "Error while adding/updating food", it)
|
||||||
|
ret = Result.failure()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
aapsLogger.error(LTag.DATAFOOD, "Error parsing food", jsonFood.toString())
|
||||||
|
ret = Result.failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,359 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.food;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.IBinder;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.j256.ormlite.android.apptools.OpenHelperManager;
|
|
||||||
import com.j256.ormlite.android.apptools.OrmLiteBaseService;
|
|
||||||
import com.j256.ormlite.dao.Dao;
|
|
||||||
import com.j256.ormlite.dao.DaoManager;
|
|
||||||
import com.j256.ormlite.support.ConnectionSource;
|
|
||||||
import com.j256.ormlite.table.TableUtils;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
|
||||||
import info.nightscout.androidaps.db.ICallback;
|
|
||||||
import info.nightscout.androidaps.events.Event;
|
|
||||||
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
|
|
||||||
import info.nightscout.androidaps.events.EventNsFood;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mike on 24.09.2017.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject RxBusWrapper rxBus;
|
|
||||||
@Inject FabricPrivacy fabricPrivacy;
|
|
||||||
@Inject AapsSchedulers aapsSchedulers;
|
|
||||||
|
|
||||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
|
|
||||||
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
private static ScheduledFuture<?> scheduledFoodEventPost = null;
|
|
||||||
|
|
||||||
public FoodService(HasAndroidInjector injector) {
|
|
||||||
injector.androidInjector().inject(this);
|
|
||||||
onCreate();
|
|
||||||
dbInitialize();
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventNsFood.class)
|
|
||||||
.observeOn(aapsSchedulers.getIo())
|
|
||||||
.subscribe(event -> {
|
|
||||||
int mode = event.getMode();
|
|
||||||
JSONArray array = event.getFoods();
|
|
||||||
if (mode == EventNsFood.Companion.getADD() || mode == EventNsFood.Companion.getUPDATE())
|
|
||||||
this.createFoodFromJsonIfNotExists(array);
|
|
||||||
else
|
|
||||||
this.deleteNS(array);
|
|
||||||
}, fabricPrivacy::logException)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is a simple re-implementation of the database create and up/downgrade functionality
|
|
||||||
* in SQLiteOpenHelper#getDatabaseLocked method.
|
|
||||||
* <p>
|
|
||||||
* It is implemented to be able to late initialize separate plugins of the application.
|
|
||||||
*/
|
|
||||||
protected void dbInitialize() {
|
|
||||||
DatabaseHelper helper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
|
|
||||||
int newVersion = helper.getNewVersion();
|
|
||||||
int oldVersion = helper.getOldVersion();
|
|
||||||
|
|
||||||
if (oldVersion > newVersion) {
|
|
||||||
onDowngrade(this.getConnectionSource(), oldVersion, newVersion);
|
|
||||||
} else {
|
|
||||||
onUpgrade(this.getConnectionSource(), oldVersion, newVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dao<Food, Long> getDao() {
|
|
||||||
try {
|
|
||||||
return DaoManager.createDao(this.getConnectionSource(), Food.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Cannot create Dao for Food.class");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
try {
|
|
||||||
aapsLogger.info(LTag.DATAFOOD, "onCreate");
|
|
||||||
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Can't create database", e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onUpgrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
|
|
||||||
aapsLogger.info(LTag.DATAFOOD, "onUpgrade");
|
|
||||||
// this.resetFood();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDowngrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
|
|
||||||
// this method is not supported right now
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetFood() {
|
|
||||||
try {
|
|
||||||
TableUtils.dropTable(this.getConnectionSource(), Food.class, true);
|
|
||||||
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
scheduleFoodChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A place to centrally register events to be posted, if any data changed.
|
|
||||||
* This should be implemented in an abstract service-class.
|
|
||||||
* <p>
|
|
||||||
* We do need to make sure, that ICallback is extended to be able to handle multiple
|
|
||||||
* events, or handle a list of events.
|
|
||||||
* <p>
|
|
||||||
* on some methods the earliestDataChange event is handled separatly, in that it is checked if it is
|
|
||||||
* set to null by another event already (eg. scheduleExtendedBolusChange).
|
|
||||||
*
|
|
||||||
* @param event
|
|
||||||
* @param eventWorker
|
|
||||||
* @param callback
|
|
||||||
*/
|
|
||||||
private void scheduleEvent(final Event event, ScheduledExecutorService eventWorker,
|
|
||||||
final ICallback callback) {
|
|
||||||
|
|
||||||
class PostRunnable implements Runnable {
|
|
||||||
public void run() {
|
|
||||||
aapsLogger.debug(LTag.DATAFOOD, "Firing EventFoodChange");
|
|
||||||
rxBus.send(event);
|
|
||||||
callback.setPost(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// prepare task for execution in 1 sec
|
|
||||||
// cancel waiting task to prevent sending multiple posts
|
|
||||||
if (callback.getPost() != null)
|
|
||||||
callback.getPost().cancel(false);
|
|
||||||
Runnable task = new PostRunnable();
|
|
||||||
final int sec = 1;
|
|
||||||
callback.setPost(eventWorker.schedule(task, sec, TimeUnit.SECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedule a foodChange Event.
|
|
||||||
*/
|
|
||||||
public void scheduleFoodChange() {
|
|
||||||
this.scheduleEvent(new EventFoodDatabaseChanged(), foodEventWorker, new ICallback() {
|
|
||||||
@Override
|
|
||||||
public void setPost(ScheduledFuture<?> post) {
|
|
||||||
scheduledFoodEventPost = post;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScheduledFuture<?> getPost() {
|
|
||||||
return scheduledFoodEventPost;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Food> getFoodData() {
|
|
||||||
try {
|
|
||||||
return this.getDao().queryForAll();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"_id": "551ee3ad368e06e80856e6a9",
|
|
||||||
"type": "food",
|
|
||||||
"category": "Zakladni",
|
|
||||||
"subcategory": "Napoje",
|
|
||||||
"name": "Mleko",
|
|
||||||
"portion": 250,
|
|
||||||
"carbs": 12,
|
|
||||||
"gi": 1,
|
|
||||||
"created_at": "2015-04-14T06:59:16.500Z",
|
|
||||||
"unit": "ml"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public void createFoodFromJsonIfNotExists(JSONObject json) {
|
|
||||||
try {
|
|
||||||
Food food = Food.createFromJson(json);
|
|
||||||
this.createFoodFromJsonIfNotExists(food);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createFoodFromJsonIfNotExists(JSONArray array) {
|
|
||||||
try {
|
|
||||||
for (int n = 0; n < array.length(); n++) {
|
|
||||||
JSONObject json = array.getJSONObject(n);
|
|
||||||
Food food = Food.createFromJson(json);
|
|
||||||
this.createFoodFromJsonIfNotExists(food);
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createFoodFromJsonIfNotExists(Food food) {
|
|
||||||
this.createOrUpdateByNS(food);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteNS(JSONObject json) {
|
|
||||||
try {
|
|
||||||
String _id = json.getString("_id");
|
|
||||||
this.deleteByNSId(_id);
|
|
||||||
} catch (JSONException | SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteNS(JSONArray array) {
|
|
||||||
try {
|
|
||||||
for (int n = 0; n < array.length(); n++) {
|
|
||||||
JSONObject json = array.getJSONObject(n);
|
|
||||||
this.deleteNS(json);
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* deletes an entry by its NS Id.
|
|
||||||
* <p>
|
|
||||||
* Basically a convenience method for findByNSId and delete.
|
|
||||||
*
|
|
||||||
* @param _id
|
|
||||||
*/
|
|
||||||
public void deleteByNSId(String _id) throws SQLException {
|
|
||||||
Food stored = this.findByNSId(_id);
|
|
||||||
if (stored != null) {
|
|
||||||
aapsLogger.debug(LTag.DATAFOOD, "Removing Food record from database: " + stored.toString());
|
|
||||||
this.delete(stored);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* deletes the food and sends the foodChange Event
|
|
||||||
* <p>
|
|
||||||
* should be moved ot a Service
|
|
||||||
*
|
|
||||||
* @param food
|
|
||||||
*/
|
|
||||||
public void delete(Food food) {
|
|
||||||
try {
|
|
||||||
this.getDao().delete(food);
|
|
||||||
this.scheduleFoodChange();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create of update a food record by the NS (Nightscout) Id.
|
|
||||||
*
|
|
||||||
* @param food
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean createOrUpdateByNS(Food food) {
|
|
||||||
// find by NS _id
|
|
||||||
if (food._id != null && !food._id.equals("")) {
|
|
||||||
Food old = this.findByNSId(food._id);
|
|
||||||
|
|
||||||
if (old != null) {
|
|
||||||
if (!old.isEqual(food)) {
|
|
||||||
this.delete(old); // need to delete/create because date may change too
|
|
||||||
old.copyFrom(food);
|
|
||||||
this.create(old);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.createOrUpdate(food);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createOrUpdate(Food food) {
|
|
||||||
try {
|
|
||||||
this.getDao().createOrUpdate(food);
|
|
||||||
aapsLogger.debug(LTag.DATAFOOD, "Created or Updated: " + food.toString());
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unable to createOrUpdate Food", e);
|
|
||||||
}
|
|
||||||
this.scheduleFoodChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void create(Food food) {
|
|
||||||
try {
|
|
||||||
this.getDao().create(food);
|
|
||||||
aapsLogger.debug(LTag.DATAFOOD, "New record: " + food.toString());
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unable to create Food", e);
|
|
||||||
}
|
|
||||||
this.scheduleFoodChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* finds food by its NS Id.
|
|
||||||
*
|
|
||||||
* @param _id
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public Food findByNSId(String _id) {
|
|
||||||
try {
|
|
||||||
List<Food> list = this.getDao().queryForEq("_id", _id);
|
|
||||||
|
|
||||||
if (list.size() == 1) { // really? if there are more then one result, then we do not return anything...
|
|
||||||
return list.get(0);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent intent) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -108,6 +108,7 @@ class ImportExportPrefs @Inject constructor(
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
private fun detectUserName(context: Context): String {
|
private fun detectUserName(context: Context): String {
|
||||||
// based on https://medium.com/@pribble88/how-to-get-an-android-device-nickname-4b4700b3068c
|
// based on https://medium.com/@pribble88/how-to-get-an-android-device-nickname-4b4700b3068c
|
||||||
val n1 = Settings.System.getString(context.contentResolver, "bluetooth_name")
|
val n1 = Settings.System.getString(context.contentResolver, "bluetooth_name")
|
||||||
|
@ -346,7 +347,7 @@ class ImportExportPrefs @Inject constructor(
|
||||||
|
|
||||||
private fun restartAppAfterImport(context: Context) {
|
private fun restartAppAfterImport(context: Context) {
|
||||||
sp.putBoolean(R.string.key_setupwizard_processed, true)
|
sp.putBoolean(R.string.key_setupwizard_processed, true)
|
||||||
OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
|
OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp)) {
|
||||||
uel.log(Action.IMPORT_SETTINGS)
|
uel.log(Action.IMPORT_SETTINGS)
|
||||||
log.debug(LTag.CORE, "Exiting")
|
log.debug(LTag.CORE, "Exiting")
|
||||||
rxBus.send(EventAppExit())
|
rxBus.send(EventAppExit())
|
||||||
|
@ -355,14 +356,13 @@ class ImportExportPrefs @Inject constructor(
|
||||||
}
|
}
|
||||||
System.runFinalization()
|
System.runFinalization()
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exportUserEntriesCsv(activity: FragmentActivity, listEntries: Single<List<UserEntry>>) {
|
override fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single<List<UserEntry>>) {
|
||||||
val entries = listEntries.blockingGet()
|
val entries = singleEntries.blockingGet()
|
||||||
prefFileList.ensureExportDirExists()
|
prefFileList.ensureExportDirExists()
|
||||||
val newFile = prefFileList.newExportXmlFile()
|
val newFile = prefFileList.newExportXmlFile()
|
||||||
//log.debug("XXXXX " + classicPrefsFormat.UserEntriesToCsv(entries))
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
classicPrefsFormat.saveCsv(newFile, entries)
|
classicPrefsFormat.saveCsv(newFile, entries)
|
||||||
|
|
|
@ -16,7 +16,6 @@ import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
@ -34,7 +33,6 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
@Inject lateinit var foodPlugin: FoodPlugin
|
|
||||||
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
|
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@ -70,7 +68,6 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
databaseHelper.resetDatabases()
|
databaseHelper.resetDatabases()
|
||||||
// should be handled by Plugin-Interface and
|
// should be handled by Plugin-Interface and
|
||||||
// additional service interface and plugin registry
|
// additional service interface and plugin registry
|
||||||
foodPlugin.service?.resetFood()
|
|
||||||
treatmentsPlugin.service.resetTreatments()
|
treatmentsPlugin.service.resetTreatments()
|
||||||
repository.clearDatabases()
|
repository.clearDatabases()
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.db.DbRequest;
|
import info.nightscout.androidaps.db.DbRequest;
|
||||||
import info.nightscout.androidaps.events.EventAppExit;
|
import info.nightscout.androidaps.events.EventAppExit;
|
||||||
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
||||||
import info.nightscout.androidaps.events.EventNsFood;
|
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
|
@ -636,39 +635,8 @@ public class NSClientService extends DaggerService {
|
||||||
}
|
}
|
||||||
if (data.has("food")) {
|
if (data.has("food")) {
|
||||||
JSONArray foods = data.getJSONArray("food");
|
JSONArray foods = data.getJSONArray("food");
|
||||||
JSONArray removedFoods = new JSONArray();
|
if (foods.length() > 0) rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods"));
|
||||||
JSONArray updatedFoods = new JSONArray();
|
handleFood(foods, isDelta);
|
||||||
JSONArray addedFoods = new JSONArray();
|
|
||||||
if (foods.length() > 0)
|
|
||||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods"));
|
|
||||||
for (Integer index = 0; index < foods.length(); index++) {
|
|
||||||
JSONObject jsonFood = foods.getJSONObject(index);
|
|
||||||
|
|
||||||
// remove from upload queue if Ack is failing
|
|
||||||
uploadQueue.removeID(jsonFood);
|
|
||||||
|
|
||||||
String action = JsonHelper.safeGetString(jsonFood, "action");
|
|
||||||
|
|
||||||
if (action == null) {
|
|
||||||
addedFoods.put(jsonFood);
|
|
||||||
} else if (action.equals("update")) {
|
|
||||||
updatedFoods.put(jsonFood);
|
|
||||||
} else if (action.equals("remove")) {
|
|
||||||
removedFoods.put(jsonFood);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (removedFoods.length() > 0) {
|
|
||||||
EventNsFood evt = new EventNsFood(EventNsFood.Companion.getREMOVE(), removedFoods);
|
|
||||||
rxBus.send(evt);
|
|
||||||
}
|
|
||||||
if (updatedFoods.length() > 0) {
|
|
||||||
EventNsFood evt = new EventNsFood(EventNsFood.Companion.getUPDATE(), updatedFoods);
|
|
||||||
rxBus.send(evt);
|
|
||||||
}
|
|
||||||
if (addedFoods.length() > 0) {
|
|
||||||
EventNsFood evt = new EventNsFood(EventNsFood.Companion.getADD(), addedFoods);
|
|
||||||
rxBus.send(evt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (data.has("mbgs")) {
|
if (data.has("mbgs")) {
|
||||||
JSONArray mbgs = data.getJSONArray("mbgs");
|
JSONArray mbgs = data.getJSONArray("mbgs");
|
||||||
|
@ -881,6 +849,16 @@ public class NSClientService extends DaggerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleFood(JSONArray foods, boolean isDelta) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString("foods", foods.toString());
|
||||||
|
bundle.putBoolean("delta", isDelta);
|
||||||
|
Intent intent = new Intent(Intents.ACTION_FOOD);
|
||||||
|
intent.putExtras(bundle);
|
||||||
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||||
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||||
|
}
|
||||||
|
|
||||||
public void handleNewCal(JSONArray cals, boolean isDelta) {
|
public void handleNewCal(JSONArray cals, boolean isDelta) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putString("cals", cals.toString());
|
bundle.putString("cals", cals.toString());
|
||||||
|
|
|
@ -12,6 +12,7 @@ import dagger.android.DaggerBroadcastReceiver
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.BundleLogger
|
import info.nightscout.androidaps.logging.BundleLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||||
|
@ -21,7 +22,6 @@ import info.nightscout.androidaps.utils.extensions.copyDouble
|
||||||
import info.nightscout.androidaps.utils.extensions.copyInt
|
import info.nightscout.androidaps.utils.extensions.copyInt
|
||||||
import info.nightscout.androidaps.utils.extensions.copyLong
|
import info.nightscout.androidaps.utils.extensions.copyLong
|
||||||
import info.nightscout.androidaps.utils.extensions.copyString
|
import info.nightscout.androidaps.utils.extensions.copyString
|
||||||
import org.json.JSONObject
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
open class DataReceiver : DaggerBroadcastReceiver() {
|
open class DataReceiver : DaggerBroadcastReceiver() {
|
||||||
|
@ -87,6 +87,9 @@ open class DataReceiver : DaggerBroadcastReceiver() {
|
||||||
Intents.DEXCOM_BG ->
|
Intents.DEXCOM_BG ->
|
||||||
OneTimeWorkRequest.Builder(DexcomPlugin.DexcomWorker::class.java)
|
OneTimeWorkRequest.Builder(DexcomPlugin.DexcomWorker::class.java)
|
||||||
.setInputData(bundleInputData(bundle, intent)).build()
|
.setInputData(bundleInputData(bundle, intent)).build()
|
||||||
|
Intents.ACTION_FOOD ->
|
||||||
|
OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker::class.java)
|
||||||
|
.setInputData(bundleInputData(bundle, intent)).build()
|
||||||
Intents.ACTION_NEW_TREATMENT,
|
Intents.ACTION_NEW_TREATMENT,
|
||||||
Intents.ACTION_CHANGED_TREATMENT,
|
Intents.ACTION_CHANGED_TREATMENT,
|
||||||
Intents.ACTION_REMOVED_TREATMENT,
|
Intents.ACTION_REMOVED_TREATMENT,
|
||||||
|
@ -105,6 +108,7 @@ open class DataReceiver : DaggerBroadcastReceiver() {
|
||||||
Data.Builder().putLong(STORE_KEY, bundleStore.store(bundle)).putString(ACTION_KEY, intent.action).build()
|
Data.Builder().putLong(STORE_KEY, bundleStore.store(bundle)).putString(ACTION_KEY, intent.action).build()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val STORE_KEY = "storeKey"
|
const val STORE_KEY = "storeKey"
|
||||||
const val ACTION_KEY = "action"
|
const val ACTION_KEY = "action"
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ interface Intents {
|
||||||
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
|
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
|
||||||
const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG"
|
const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG"
|
||||||
const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL"
|
const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL"
|
||||||
|
const val ACTION_FOOD = "info.nightscout.client.FOOD"
|
||||||
|
|
||||||
// xDrip -> App
|
// xDrip -> App
|
||||||
const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate"
|
const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate"
|
||||||
|
|
|
@ -4,7 +4,17 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment">
|
tools:context="info.nightscout.androidaps.plugins.general.food.TreatmentsFoodFragment">
|
||||||
|
|
||||||
|
<info.nightscout.androidaps.utils.ui.SingleClickButton
|
||||||
|
android:id="@+id/refresh_from_nightscout"
|
||||||
|
style="?android:attr/buttonStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:drawableStart="@drawable/ic_refresh"
|
||||||
|
android:text="@string/refresheventsfromnightscout"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -48,6 +58,7 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
android:text="@string/category" />
|
android:text="@string/category" />
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
|
@ -65,6 +76,7 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
android:text="@string/subcategory" />
|
android:text="@string/subcategory" />
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
card_view:cardBackgroundColor="@color/cardColorBackground"
|
card_view:cardBackgroundColor="?android:colorBackground">
|
||||||
card_view:cardCornerRadius="6dp"
|
|
||||||
card_view:cardUseCompatPadding="true"
|
|
||||||
card_view:contentPadding="6dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -26,21 +24,24 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="Name"
|
android:text="Name"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/portion"
|
android:id="@+id/portion"
|
||||||
android:layout_width="60dp"
|
android:layout_width="60dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:text="Portion" />
|
android:text="Portion"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/carbs"
|
android:id="@+id/carbs"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:text="Carbs" />
|
android:text="Carbs"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -56,21 +57,24 @@
|
||||||
android:layout_width="70dp"
|
android:layout_width="70dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:text="Fat" />
|
android:text="Fat"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/protein"
|
android:id="@+id/protein"
|
||||||
android:layout_width="70dp"
|
android:layout_width="70dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:text="Protein" />
|
android:text="Protein"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/energy"
|
android:id="@+id/energy"
|
||||||
android:layout_width="70dp"
|
android:layout_width="70dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:text="Energy" />
|
android:text="Energy"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/ns_sign"
|
android:id="@+id/ns_sign"
|
||||||
|
@ -79,7 +83,8 @@
|
||||||
android:width="30dp"
|
android:width="30dp"
|
||||||
android:text="NS"
|
android:text="NS"
|
||||||
android:textAlignment="viewEnd"
|
android:textAlignment="viewEnd"
|
||||||
android:textColor="@color/colorSetTempButton" />
|
android:textColor="@color/colorSetTempButton"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/remove"
|
android:id="@+id/remove"
|
||||||
|
@ -93,6 +98,15 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="2dip"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginRight="5dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:background="@color/list_delimiter" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
|
@ -317,7 +317,7 @@
|
||||||
<string name="openapsma_autosensdata_label">Autosens data</string>
|
<string name="openapsma_autosensdata_label">Autosens data</string>
|
||||||
<string name="openapsma_scriptdebugdata_label">Script debug</string>
|
<string name="openapsma_scriptdebugdata_label">Script debug</string>
|
||||||
<string name="openapsama_useautosens">Use Autosens feature</string>
|
<string name="openapsama_useautosens">Use Autosens feature</string>
|
||||||
<string name="refresheventsfromnightscout">Refresh events from NS</string>
|
<string name="refresheventsfromnightscout">Refresh from NS</string>
|
||||||
<string name="deletefuturetreatments">Delete treatments in the future</string>
|
<string name="deletefuturetreatments">Delete treatments in the future</string>
|
||||||
<string name="actions_shortname">ACT</string>
|
<string name="actions_shortname">ACT</string>
|
||||||
<string name="configbuilder_shortname">CONF</string>
|
<string name="configbuilder_shortname">CONF</string>
|
||||||
|
|
|
@ -14,5 +14,5 @@ interface ImportExportPrefsInterface {
|
||||||
fun prefsFileExists(): Boolean
|
fun prefsFileExists(): Boolean
|
||||||
fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable)
|
fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable)
|
||||||
fun exportSharedPreferences(f: Fragment)
|
fun exportSharedPreferences(f: Fragment)
|
||||||
fun exportUserEntriesCsv(activity: FragmentActivity, entries: Single<List<UserEntry>>)
|
fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single<List<UserEntry>>)
|
||||||
}
|
}
|
|
@ -5,7 +5,6 @@ import org.json.JSONObject
|
||||||
|
|
||||||
object JsonHelper {
|
object JsonHelper {
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun safeGetObject(json: JSONObject?, fieldName: String, defaultValue: Any): Any {
|
fun safeGetObject(json: JSONObject?, fieldName: String, defaultValue: Any): Any {
|
||||||
var result = defaultValue
|
var result = defaultValue
|
||||||
if (json != null && json.has(fieldName)) {
|
if (json != null && json.has(fieldName)) {
|
||||||
|
@ -17,7 +16,6 @@ object JsonHelper {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun safeGetJSONObject(json: JSONObject?, fieldName: String, defaultValue: JSONObject?): JSONObject? {
|
fun safeGetJSONObject(json: JSONObject?, fieldName: String, defaultValue: JSONObject?): JSONObject? {
|
||||||
var result = defaultValue
|
var result = defaultValue
|
||||||
if (json != null && json.has(fieldName)) {
|
if (json != null && json.has(fieldName)) {
|
||||||
|
@ -53,7 +51,6 @@ object JsonHelper {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun safeGetStringAllowNull(json: JSONObject?, fieldName: String, defaultValue: String?): String? {
|
fun safeGetStringAllowNull(json: JSONObject?, fieldName: String, defaultValue: String?): String? {
|
||||||
var result = defaultValue
|
var result = defaultValue
|
||||||
if (json != null && json.has(fieldName)) {
|
if (json != null && json.has(fieldName)) {
|
||||||
|
@ -77,7 +74,6 @@ object JsonHelper {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun safeGetDoubleAllowNull(json: JSONObject?, fieldName: String): Double? {
|
fun safeGetDoubleAllowNull(json: JSONObject?, fieldName: String): Double? {
|
||||||
var result: Double? = null
|
var result: Double? = null
|
||||||
if (json != null && json.has(fieldName)) {
|
if (json != null && json.has(fieldName)) {
|
||||||
|
@ -89,7 +85,6 @@ object JsonHelper {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun safeGetDouble(json: JSONObject?, fieldName: String, defaultValue: Double): Double {
|
fun safeGetDouble(json: JSONObject?, fieldName: String, defaultValue: Double): Double {
|
||||||
var result = defaultValue
|
var result = defaultValue
|
||||||
if (json != null && json.has(fieldName)) {
|
if (json != null && json.has(fieldName)) {
|
||||||
|
@ -105,7 +100,6 @@ object JsonHelper {
|
||||||
fun safeGetInt(json: JSONObject?, fieldName: String): Int =
|
fun safeGetInt(json: JSONObject?, fieldName: String): Int =
|
||||||
safeGetInt(json, fieldName, 0)
|
safeGetInt(json, fieldName, 0)
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun safeGetInt(json: JSONObject?, fieldName: String, defaultValue: Int): Int {
|
fun safeGetInt(json: JSONObject?, fieldName: String, defaultValue: Int): Int {
|
||||||
var result = defaultValue
|
var result = defaultValue
|
||||||
if (json != null && json.has(fieldName)) {
|
if (json != null && json.has(fieldName)) {
|
||||||
|
@ -117,6 +111,17 @@ object JsonHelper {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun safeGetIntAllowNull(json: JSONObject?, fieldName: String): Int? {
|
||||||
|
var result : Int? = null
|
||||||
|
if (json != null && json.has(fieldName)) {
|
||||||
|
try {
|
||||||
|
result = json.getInt(fieldName)
|
||||||
|
} catch (ignored: JSONException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun safeGetLong(json: JSONObject?, fieldName: String): Long {
|
fun safeGetLong(json: JSONObject?, fieldName: String): Long {
|
||||||
var result: Long = 0
|
var result: Long = 0
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package info.nightscout.androidaps.utils.extensions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
|
import info.nightscout.androidaps.utils.JsonHelper
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
fun foodFromJson(jsonObject: JSONObject): Food? {
|
||||||
|
if ("food" == JsonHelper.safeGetString(jsonObject, "type")) {
|
||||||
|
val name = JsonHelper.safeGetStringAllowNull(jsonObject, "name", null) ?: return null
|
||||||
|
val category = JsonHelper.safeGetStringAllowNull(jsonObject, "category", null)
|
||||||
|
val subCategory = JsonHelper.safeGetStringAllowNull(jsonObject, "subcategory", null)
|
||||||
|
val unit = JsonHelper.safeGetString(jsonObject, "unit", "")
|
||||||
|
val portion = JsonHelper.safeGetDoubleAllowNull(jsonObject, "portion") ?: return null
|
||||||
|
val carbs = JsonHelper.safeGetIntAllowNull(jsonObject, "carbs") ?: return null
|
||||||
|
val gi = JsonHelper.safeGetIntAllowNull(jsonObject, "gi")
|
||||||
|
val energy = JsonHelper.safeGetIntAllowNull(jsonObject, "energy")
|
||||||
|
val protein = JsonHelper.safeGetIntAllowNull(jsonObject, "protein")
|
||||||
|
val fat = JsonHelper.safeGetIntAllowNull(jsonObject, "fat")
|
||||||
|
val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null
|
||||||
|
val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true)
|
||||||
|
|
||||||
|
val food = Food(
|
||||||
|
name = name,
|
||||||
|
category = category,
|
||||||
|
subCategory = subCategory,
|
||||||
|
unit = unit,
|
||||||
|
portion = portion,
|
||||||
|
carbs = carbs,
|
||||||
|
gi = gi,
|
||||||
|
energy = energy,
|
||||||
|
protein = protein,
|
||||||
|
fat = fat,
|
||||||
|
isValid = isValid
|
||||||
|
)
|
||||||
|
food.interfaceIDs.nightscoutId = id
|
||||||
|
return food
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -6,13 +6,14 @@ import androidx.room.TypeConverters
|
||||||
import info.nightscout.androidaps.database.daos.*
|
import info.nightscout.androidaps.database.daos.*
|
||||||
import info.nightscout.androidaps.database.entities.*
|
import info.nightscout.androidaps.database.entities.*
|
||||||
|
|
||||||
const val DATABASE_VERSION = 6
|
const val DATABASE_VERSION = 7
|
||||||
|
|
||||||
@Database(version = DATABASE_VERSION,
|
@Database(version = DATABASE_VERSION,
|
||||||
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,
|
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,
|
||||||
EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class,
|
EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class,
|
||||||
TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class,
|
TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class,
|
||||||
MealLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class],
|
MealLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class,
|
||||||
|
Food::class],
|
||||||
exportSchema = true)
|
exportSchema = true)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
internal abstract class AppDatabase : RoomDatabase() {
|
internal abstract class AppDatabase : RoomDatabase() {
|
||||||
|
@ -53,4 +54,6 @@ internal abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
abstract val preferenceChangeDao: PreferenceChangeDao
|
abstract val preferenceChangeDao: PreferenceChangeDao
|
||||||
|
|
||||||
|
abstract val foodDao: FoodDao
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.database
|
package info.nightscout.androidaps.database
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||||
|
@ -170,6 +171,14 @@ class AppRepository @Inject internal constructor(
|
||||||
database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to)
|
database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
|
|
||||||
|
// FOOD
|
||||||
|
fun getFoodData(): Single<List<Food>> =
|
||||||
|
database.foodDao.getFoodData()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
|
||||||
|
fun deleteAllFoods() =
|
||||||
|
database.foodDao.deleteAllEntries()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("USELESS_CAST")
|
@Suppress("USELESS_CAST")
|
||||||
|
|
|
@ -34,4 +34,10 @@ open class DatabaseModule {
|
||||||
database.execSQL("CREATE TABLE userEntry (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `s` TEXT NOT NULL, `values` TEXT NOT NULL)")
|
database.execSQL("CREATE TABLE userEntry (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `s` TEXT NOT NULL, `values` TEXT NOT NULL)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val migration6to7 = object : Migration(6, 7) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("CREATE TABLE IF NOT EXISTS foods (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `name` TEXT NOT NULL, `category` TEXT, `subCategory` TEXT, `portion` REAL NOT NULL, `carbs` INTEGER NOT NULL, `fat` INTEGER, `protein` INTEGER, `energy` INTEGER, `unit` TEXT NOT NULL, `gi` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `foods`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,5 +24,6 @@ internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, val datab
|
||||||
val versionChangeDao: VersionChangeDao = DelegatedVersionChangeDao(changes, database.versionChangeDao)
|
val versionChangeDao: VersionChangeDao = DelegatedVersionChangeDao(changes, database.versionChangeDao)
|
||||||
val userEntryDao: UserEntryDao = DelegatedUserEntryDao(changes, database.userEntryDao)
|
val userEntryDao: UserEntryDao = DelegatedUserEntryDao(changes, database.userEntryDao)
|
||||||
val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao)
|
val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao)
|
||||||
|
val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao)
|
||||||
fun clearAllTables() = database.clearAllTables()
|
fun clearAllTables() = database.clearAllTables()
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ const val TABLE_CARBS = "carbs"
|
||||||
const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches"
|
const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches"
|
||||||
const val TABLE_EXTENDED_BOLUSES = "extendedBoluses"
|
const val TABLE_EXTENDED_BOLUSES = "extendedBoluses"
|
||||||
const val TABLE_GLUCOSE_VALUES = "glucoseValues"
|
const val TABLE_GLUCOSE_VALUES = "glucoseValues"
|
||||||
|
const val TABLE_FOODS = "foods"
|
||||||
const val TABLE_MEAL_LINKS = "mealLinks"
|
const val TABLE_MEAL_LINKS = "mealLinks"
|
||||||
const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks"
|
const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks"
|
||||||
const val TABLE_PROFILE_SWITCHES = "profileSwitches"
|
const val TABLE_PROFILE_SWITCHES = "profileSwitches"
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package info.nightscout.androidaps.database.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import info.nightscout.androidaps.database.TABLE_FOODS
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
import io.reactivex.Single
|
||||||
|
|
||||||
|
@Suppress("FunctionName")
|
||||||
|
@Dao
|
||||||
|
internal interface FoodDao : TraceableDao<Food> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM $TABLE_FOODS WHERE id = :id")
|
||||||
|
override fun findById(id: Long): Food?
|
||||||
|
|
||||||
|
@Query("DELETE FROM $TABLE_FOODS")
|
||||||
|
override fun deleteAllEntries()
|
||||||
|
|
||||||
|
@Query("SELECT * FROM $TABLE_FOODS WHERE nightscoutId = :nsId AND referenceId IS NULL")
|
||||||
|
fun findByNSId(nsId: String): Food?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM $TABLE_FOODS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC")
|
||||||
|
fun getFoodData(): Single<List<Food>>
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import androidx.room.Insert
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import info.nightscout.androidaps.database.daos.workaround.TraceableDaoWorkaround
|
import info.nightscout.androidaps.database.daos.workaround.TraceableDaoWorkaround
|
||||||
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
|
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
|
||||||
import io.reactivex.Single
|
|
||||||
|
|
||||||
internal interface TraceableDao<T : TraceableDBEntry> : TraceableDaoWorkaround<T> {
|
internal interface TraceableDao<T : TraceableDBEntry> : TraceableDaoWorkaround<T> {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package info.nightscout.androidaps.database.daos.delegated
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.database.daos.FoodDao
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
import info.nightscout.androidaps.database.interfaces.DBEntry
|
||||||
|
|
||||||
|
internal class DelegatedFoodDao(changes: MutableList<DBEntry>, private val dao: FoodDao) : DelegatedDao(changes), FoodDao by dao {
|
||||||
|
|
||||||
|
override fun insertNewEntry(food: Food): Long {
|
||||||
|
changes.add(food)
|
||||||
|
return dao.insertNewEntry(food)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateExistingEntry(food: Food): Long {
|
||||||
|
changes.add(food)
|
||||||
|
return dao.updateExistingEntry(food)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package info.nightscout.androidaps.database.entities
|
||||||
|
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import info.nightscout.androidaps.database.TABLE_FOODS
|
||||||
|
import info.nightscout.androidaps.database.embedments.InterfaceIDs
|
||||||
|
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
|
||||||
|
|
||||||
|
@Entity(tableName = TABLE_FOODS,
|
||||||
|
foreignKeys = [ForeignKey(
|
||||||
|
entity = Food::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["referenceId"])],
|
||||||
|
indices = [Index("referenceId")])
|
||||||
|
data class Food(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
override var id: Long = 0,
|
||||||
|
override var version: Int = 0,
|
||||||
|
override var dateCreated: Long = -1,
|
||||||
|
override var isValid: Boolean = true,
|
||||||
|
override var referenceId: Long? = null,
|
||||||
|
@Embedded
|
||||||
|
override var interfaceIDs_backing: InterfaceIDs? = 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
|
||||||
|
|
||||||
|
) : TraceableDBEntry {
|
||||||
|
|
||||||
|
fun isEqual(other: Food): Boolean {
|
||||||
|
if (isValid != other.isValid) return false
|
||||||
|
if (portion != other.portion) return false
|
||||||
|
if (carbs != other.carbs) return false
|
||||||
|
if (fat != other.fat) return false
|
||||||
|
if (protein != other.protein) return false
|
||||||
|
if (energy != other.energy) return false
|
||||||
|
if (gi != other.gi) return false
|
||||||
|
if (name != other.name) return false
|
||||||
|
if (category != other.category) return false
|
||||||
|
if (subCategory != other.subCategory) return false
|
||||||
|
return unit == other.unit
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyFrom(other: Food) {
|
||||||
|
isValid = other.isValid
|
||||||
|
name = other.name
|
||||||
|
category = other.category
|
||||||
|
subCategory = other.subCategory
|
||||||
|
portion = other.portion
|
||||||
|
carbs = other.carbs
|
||||||
|
fat = other.fat
|
||||||
|
protein = other.protein
|
||||||
|
energy = other.energy
|
||||||
|
unit = other.unit
|
||||||
|
gi = other.gi
|
||||||
|
interfaceIDs.nightscoutId = other.interfaceIDs.nightscoutId
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -103,6 +103,7 @@ data class UserEntry(
|
||||||
@SerializedName("TT_DELETED_FROM_NS") TT_DELETED_FROM_NS (ColorGroup.TT),
|
@SerializedName("TT_DELETED_FROM_NS") TT_DELETED_FROM_NS (ColorGroup.TT),
|
||||||
@SerializedName("CAREPORTAL_DELETED_FROM_NS") CAREPORTAL_DELETED_FROM_NS (ColorGroup.Careportal),
|
@SerializedName("CAREPORTAL_DELETED_FROM_NS") CAREPORTAL_DELETED_FROM_NS (ColorGroup.Careportal),
|
||||||
@SerializedName("CAREPORTAL_FROM_NS") CAREPORTAL_FROM_NS (ColorGroup.Careportal),
|
@SerializedName("CAREPORTAL_FROM_NS") CAREPORTAL_FROM_NS (ColorGroup.Careportal),
|
||||||
|
@SerializedName("FOOD_FROM_NS") FOOD_FROM_NS (ColorGroup.Careportal),
|
||||||
@SerializedName("TT_FROM_NS") TT_FROM_NS (ColorGroup.TT),
|
@SerializedName("TT_FROM_NS") TT_FROM_NS (ColorGroup.TT),
|
||||||
@SerializedName("TT_CANCELED_FROM_NS") TT_CANCELED_FROM_NS (ColorGroup.TT),
|
@SerializedName("TT_CANCELED_FROM_NS") TT_CANCELED_FROM_NS (ColorGroup.TT),
|
||||||
@SerializedName("EXPORT_CSV") EXPORT_CSV (ColorGroup.Aaps),
|
@SerializedName("EXPORT_CSV") EXPORT_CSV (ColorGroup.Aaps),
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package info.nightscout.androidaps.database.transactions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts or updates the Food
|
||||||
|
*/
|
||||||
|
class InsertOrUpdateFoodTransaction(private val food: Food) : Transaction<InsertOrUpdateFoodTransaction.TransactionResult>() {
|
||||||
|
|
||||||
|
override fun run(): TransactionResult {
|
||||||
|
val result = TransactionResult()
|
||||||
|
val current = database.foodDao.findById(food.id)
|
||||||
|
if (current == null) {
|
||||||
|
database.foodDao.insertNewEntry(food)
|
||||||
|
result.inserted.add(food)
|
||||||
|
} else {
|
||||||
|
database.foodDao.updateExistingEntry(food)
|
||||||
|
result.updated.add(food)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransactionResult {
|
||||||
|
|
||||||
|
val inserted = mutableListOf<Food>()
|
||||||
|
val updated = mutableListOf<Food>()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package info.nightscout.androidaps.database.transactions
|
||||||
|
|
||||||
|
class InvalidateFoodTransaction(val id: Long) : Transaction<Unit>() {
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
val food = database.foodDao.findById(id)
|
||||||
|
?: throw IllegalArgumentException("There is no such Food with the specified ID.")
|
||||||
|
food.isValid = false
|
||||||
|
database.foodDao.updateExistingEntry(food)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package info.nightscout.androidaps.database.transactions
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.database.entities.Food
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync the TherapyEvents from NS
|
||||||
|
*/
|
||||||
|
class SyncFoodTransaction(private val food: Food) : Transaction<SyncFoodTransaction.TransactionResult>() {
|
||||||
|
|
||||||
|
override fun run(): TransactionResult {
|
||||||
|
val result = TransactionResult()
|
||||||
|
|
||||||
|
val current: Food? =
|
||||||
|
food.interfaceIDs.nightscoutId?.let {
|
||||||
|
database.foodDao.findByNSId(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current != null) {
|
||||||
|
// nsId exists, update if different
|
||||||
|
if (!current.isEqual(food)) {
|
||||||
|
current.copyFrom(food)
|
||||||
|
database.foodDao.updateExistingEntry(current)
|
||||||
|
if (food.isValid && current.isValid) result.updated.add(current)
|
||||||
|
else if (!food.isValid && current.isValid) result.invalidated.add(current)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// not known nsId, add
|
||||||
|
database.foodDao.insertNewEntry(food)
|
||||||
|
result.inserted.add(food)
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransactionResult {
|
||||||
|
|
||||||
|
val updated = mutableListOf<Food>()
|
||||||
|
val inserted = mutableListOf<Food>()
|
||||||
|
val invalidated = mutableListOf<Food>()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue