UserEntry refactor to include XXXValueWithUnit (first test)

This commit is contained in:
Philoul 2021-04-01 18:26:13 +02:00
parent e13e5e10eb
commit a07b685e8d
10 changed files with 166 additions and 128 deletions

View file

@ -129,8 +129,14 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
//uel.log(Action.PROFILE_SWITCH, notes, XXXValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged } , XXXValueWithUnit.SimpleString(profile), XXXValueWithUnit.Percent(percent), XXXValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 }, XXXValueWithUnit.Minute(duration).takeIf { duration != 0 })
uel.log(Action.PROFILE_SWITCH, notes, ValueWithUnit(Sources.ProfileSwitchDialog), ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(profile, Units.None), ValueWithUnit(percent, Units.Percent), ValueWithUnit(timeShift, Units.H, timeShift != 0), ValueWithUnit(duration, Units.M, duration != 0))
uel.log(Action.PROFILE_SWITCH,
Sources.ProfileSwitchDialog,
notes,
XXXValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged },
XXXValueWithUnit.SimpleString(profile),
XXXValueWithUnit.Percent(percent),
XXXValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 },
XXXValueWithUnit.Minute(duration).takeIf { duration != 0 })
treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime)
})
}

View file

@ -7,13 +7,11 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.Units
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding
import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding
@ -24,7 +22,6 @@ import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.UserEntryPresentationHelper
@ -132,46 +129,11 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
val current = entries[position]
holder.binding.date.text = dateUtil.dateAndTimeAndSecondsString(current.timestamp)
holder.binding.action.text = userEntryPresentationHelper.actionToColoredString(current.action)
if (current.s != "") {
holder.binding.s.text = current.s
holder.binding.s.visibility = View.VISIBLE
} else
holder.binding.s.visibility = View.GONE
var valuesWithUnitString = ""
var rStringParam = 0
var source = Sources.Unknown
val separator = " "
for(v in current.values) {
if (rStringParam >0)
rStringParam--
else
when (v.unit) {
Units.Timestamp -> valuesWithUnitString += dateUtil.dateAndTimeAndSecondsString(v.lValue) + separator
Units.TherapyEvent -> valuesWithUnitString += translator.translate(v.sValue) + separator
Units.R_String -> {
rStringParam = v.lValue.toInt()
when (rStringParam) { //
0 -> valuesWithUnitString += resourceHelper.gs(v.iValue) + separator
1 -> valuesWithUnitString += resourceHelper.gs(v.iValue, current.values[current.values.indexOf(v)+1].value()) + separator
2 -> valuesWithUnitString += resourceHelper.gs(v.iValue, current.values[current.values.indexOf(v)+1].value(), current.values[current.values.indexOf(v)+2].value()) + separator
3 -> valuesWithUnitString += resourceHelper.gs(v.iValue, current.values[current.values.indexOf(v)+1].value(), current.values[current.values.indexOf(v)+2].value(), current.values[current.values.indexOf(v)+3].value()) + separator
4 -> rStringParam = 0
}
}
Units.Mg_Dl -> valuesWithUnitString += if (profileFunction.getUnits()==Constants.MGDL) DecimalFormatter.to0Decimal(v.dValue) + translator.translate(Units.Mg_Dl) + separator else DecimalFormatter.to1Decimal(v.dValue/Constants.MMOLL_TO_MGDL) + translator.translate(Units.Mmol_L) + separator
Units.Mmol_L -> valuesWithUnitString += if (profileFunction.getUnits()==Constants.MGDL) DecimalFormatter.to0Decimal(v.dValue*Constants.MMOLL_TO_MGDL) + translator.translate(Units.Mg_Dl) + separator else DecimalFormatter.to1Decimal(v.dValue) + translator.translate(Units.Mmol_L) + separator
Units.U_H, Units.U
-> valuesWithUnitString += DecimalFormatter.to2Decimal(v.dValue) + translator.translate(v.unit) + separator
Units.G, Units.M, Units.H, Units.Percent
-> valuesWithUnitString += v.iValue.toString() + translator.translate(v.unit) + separator
Units.Source -> source = Sources.fromString(v.sValue) // = separator + translator.translate(v.sValue)
else -> valuesWithUnitString += if (v.iValue != 0 || v.sValue != "") { v.value().toString() + separator } else ""
}
}
holder.binding.iconSource.setImageResource(userEntryPresentationHelper.iconId(source))
holder.binding.s.text = current.note
holder.binding.s.visibility = if (current.note != "") View.VISIBLE else View.GONE
holder.binding.iconSource.setImageResource(userEntryPresentationHelper.iconId(current.source))
holder.binding.iconSource.visibility = View.VISIBLE
holder.binding.values.text = valuesWithUnitString.trim()
holder.binding.values.text = userEntryPresentationHelper.listToPresentationString(current.values)
holder.binding.values.visibility = if (holder.binding.values.text != "") View.VISIBLE else View.GONE
}
@ -186,7 +148,7 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
fun filterUserEntries(list: List<UserEntry>): List<UserEntry> {
val filteredList = mutableListOf<UserEntry>()
for (ue in list) {
if (! ue.isLoop()) filteredList.add(ue)
if (! ue.source.equals(Sources.Loop)) filteredList.add(ue)
}
return filteredList
}

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.logging
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.XXXValueWithUnit
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.transactions.UserEntryTransaction
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@ -21,72 +22,77 @@ class UserEntryLogger @Inject constructor(
private val compositeDisposable = CompositeDisposable()
@Deprecated("Use XXXValueWithUnits")
fun log(action: Action, s: String? ="", vararg listvalues: ValueWithUnit) {
val values = mutableListOf<ValueWithUnit>()
for (v in listvalues){
if (v.condition) values.add(v)
}
}
fun log(action: Action, source: Sources, note: String? ="", vararg listvalues: XXXValueWithUnit?) {
compositeDisposable += repository.runTransaction(UserEntryTransaction(
action = action,
s = s ?:"",
values = values
source = source,
note = note ?:"",
values = listvalues.toList()
))
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.io)
.subscribeBy(
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $s $values") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $s $values") }
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $source $note $listvalues") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $source $note $listvalues") }
)
}
//fun log(action: Action, vararg listvalues: XXXValueWithUnit?) = Unit // TODO
//fun log(action: Action, s: String? = "", values: List<XXXValueWithUnit?>) = Unit
//fun log(action: Action, s: String? , vararg listvalues: XXXValueWithUnit?) = Unit
@Deprecated("Use XXXValueWithUnits")
fun log(action: Action, vararg listValues: ValueWithUnit) {
val values = mutableListOf<ValueWithUnit>()
for (v in listValues){
if (v.condition) values.add(v)
}
}
fun log(action: Action, source: Sources, vararg listvalues: XXXValueWithUnit?) {
compositeDisposable += repository.runTransaction(UserEntryTransaction(
action = action,
s = "",
source = source,
note = "",
values = listvalues.toList()
))
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.io)
.subscribeBy(
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $source $listvalues") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $source $listvalues") }
)
}
@Deprecated("Use XXXValueWithUnits")
fun log(action: Action, s: String? = "") {}
fun log(action: Action, source: Sources, note: String? ="") {
compositeDisposable += repository.runTransaction(UserEntryTransaction(
action = action,
source = source,
note = note ?:"",
values = mutableListOf()
))
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.io)
.subscribeBy(
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $source $note") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $source $note") }
)
}
@Deprecated("Use XXXValueWithUnits")
fun log(action: Action, s: String? = "", values: MutableList<ValueWithUnit>) {}
fun log(action: Action, source: Sources, note: String? ="", values: MutableList<XXXValueWithUnit?>) {
compositeDisposable += repository.runTransaction(UserEntryTransaction(
action = action,
source = source,
note = note ?: "",
values = values
))
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.io)
.subscribeBy(
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $values") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $values") }
)
}
fun log(action: Action, s: String? = "") {
compositeDisposable += repository.runTransaction(UserEntryTransaction(
action = action,
s = s ?:""
))
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.io)
.subscribeBy(
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action") },
onComplete = { aapsLogger.debug("USER ENTRY: $action") }
)
}
fun log(action: Action, s: String? = "", values: MutableList<ValueWithUnit>) {
compositeDisposable += repository.runTransaction(UserEntryTransaction(
action = action,
s = s ?:"",
values = values
))
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.io)
.subscribeBy(
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $s $values") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $s $values") }
onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $source $note $values") },
onComplete = { aapsLogger.debug("USER ENTRY: $action $source $note $values") }
)
}
}

View file

@ -6,7 +6,6 @@ import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.Units
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -78,34 +78,35 @@ class UserEntryPresentationHelper @Inject constructor(
private fun coloredAction(action: Action): String = "<font color='${resourceHelper.gc(colorId(action.colorGroup))}'>${translator.translate(action)}</font>"
fun listToPresentationString(list: List<XXXValueWithUnit>) =
fun listToPresentationString(list: List<XXXValueWithUnit?>) =
list.joinToString(separator = " ", transform = this::toPresentationString)
private fun toPresentationString(valueWithUnit: XXXValueWithUnit): String = when (valueWithUnit) {
is XXXValueWithUnit.Gram -> "${valueWithUnit.value} ${translator.translate(Units.G)}"
is XXXValueWithUnit.Hour -> "${valueWithUnit.value} ${translator.translate(Units.H)}"
is XXXValueWithUnit.Minute -> "${valueWithUnit.value} ${translator.translate(Units.G)}"
is XXXValueWithUnit.Percent -> "${valueWithUnit.value} ${translator.translate(Units.Percent)}"
is XXXValueWithUnit.Insulin -> DecimalFormatter.to2Decimal(valueWithUnit.value) + translator.translate(UserEntry.Units.U)
is XXXValueWithUnit.UnitPerHour -> DecimalFormatter.to2Decimal(valueWithUnit.value) + translator.translate(UserEntry.Units.U_H)
is XXXValueWithUnit.SimpleInt -> valueWithUnit.value.toString()
is XXXValueWithUnit.SimpleString -> valueWithUnit.value
is XXXValueWithUnit.StringResource -> resourceHelper.gs(valueWithUnit.value, valueWithUnit.params.map(this::toPresentationString))
private fun toPresentationString(valueWithUnit: XXXValueWithUnit?): String = when (valueWithUnit) {
is XXXValueWithUnit.Gram -> "${valueWithUnit.value} ${translator.translate(Units.G)}"
is XXXValueWithUnit.Hour -> "${valueWithUnit.value} ${translator.translate(Units.H)}"
is XXXValueWithUnit.Minute -> "${valueWithUnit.value} ${translator.translate(Units.G)}"
is XXXValueWithUnit.Percent -> "${valueWithUnit.value} ${translator.translate(Units.Percent)}"
is XXXValueWithUnit.Insulin -> DecimalFormatter.to2Decimal(valueWithUnit.value) + translator.translate(UserEntry.Units.U)
is XXXValueWithUnit.UnitPerHour -> DecimalFormatter.to2Decimal(valueWithUnit.value) + translator.translate(UserEntry.Units.U_H)
is XXXValueWithUnit.SimpleInt -> valueWithUnit.value.toString()
is XXXValueWithUnit.SimpleString -> valueWithUnit.value
is XXXValueWithUnit.StringResource -> resourceHelper.gs(valueWithUnit.value, valueWithUnit.params)
is XXXValueWithUnit.TherapyEventMeterType -> translator.translate(valueWithUnit.value)
is XXXValueWithUnit.TherapyEventTTReason -> translator.translate(valueWithUnit.value)
is XXXValueWithUnit.TherapyEventType -> translator.translate(valueWithUnit.value)
is XXXValueWithUnit.Timestamp -> dateUtil.dateAndTimeAndSecondsString(valueWithUnit.value)
is XXXValueWithUnit.TherapyEventTTReason -> translator.translate(valueWithUnit.value)
is XXXValueWithUnit.TherapyEventType -> translator.translate(valueWithUnit.value)
is XXXValueWithUnit.Timestamp -> dateUtil.dateAndTimeAndSecondsString(valueWithUnit.value)
is XXXValueWithUnit.Mgdl -> {
is XXXValueWithUnit.Mgdl -> {
if (profileFunction.getUnits() == Constants.MGDL) DecimalFormatter.to0Decimal(valueWithUnit.value) + translator.translate(Units.Mg_Dl)
else DecimalFormatter.to1Decimal(valueWithUnit.value / Constants.MMOLL_TO_MGDL) + translator.translate(Units.Mmol_L)
}
is XXXValueWithUnit.Mmoll -> {
is XXXValueWithUnit.Mmoll -> {
if (profileFunction.getUnits() == Constants.MGDL) DecimalFormatter.to0Decimal(valueWithUnit.value) + translator.translate(Units.Mmol_L)
else DecimalFormatter.to1Decimal(valueWithUnit.value * Constants.MMOLL_TO_MGDL) + translator.translate(Units.Mg_Dl)
}
XXXValueWithUnit.UNKNOWN -> ""
XXXValueWithUnit.UNKNOWN -> ""
null -> ""
}
}

View file

@ -6,7 +6,7 @@ import androidx.room.TypeConverters
import info.nightscout.androidaps.database.daos.*
import info.nightscout.androidaps.database.entities.*
const val DATABASE_VERSION = 10
const val DATABASE_VERSION = 11
@Database(version = DATABASE_VERSION,
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,

View file

@ -7,8 +7,11 @@ import info.nightscout.androidaps.database.data.TargetBlock
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.*
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.Units
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.serialisation.SealedClassHelper
import info.nightscout.androidaps.database.serialisation.fromJson
import org.json.JSONArray
import org.json.JSONObject
@ -20,6 +23,22 @@ class Converters {
@TypeConverter
fun toAction(action: String?) = action?.let { Action.fromString(it) }
@TypeConverter
fun fromSource(source: Sources?) = source?.name
@TypeConverter
fun toSource(source: String?) = source?.let { Sources.fromString(it) }
@TypeConverter
fun fromListOfXXXValueWithUnit(values: List<XXXValueWithUnit>): String = values.map(::ValueWithUnitWrapper)
.let(SealedClassHelper.gson::toJson)
@TypeConverter
fun toMutableListOfXXXValueWithUnit(string: String): List<XXXValueWithUnit> = SealedClassHelper.gson
.fromJson<List<ValueWithUnitWrapper>>(string).map { it.wrapped }
private class ValueWithUnitWrapper(val wrapped: XXXValueWithUnit)
@TypeConverter
fun fromMutableListOfValueWithUnit(values: MutableList<ValueWithUnit>): String {
val jsonArray = JSONArray()

View file

@ -2,7 +2,6 @@ package info.nightscout.androidaps.database.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import info.nightscout.androidaps.database.TABLE_USER_ENTRY
import info.nightscout.androidaps.database.interfaces.DBEntry
import info.nightscout.androidaps.database.interfaces.DBEntryWithTime
@ -15,9 +14,9 @@ data class UserEntry(
override var timestamp: Long,
override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(),
var action: Action,
var s: String,
// val sources: Sources,
var values: MutableList<ValueWithUnit>
var source: Sources,
var note: String,
var values: List<XXXValueWithUnit?>
) : DBEntry, DBEntryWithTime {
enum class Action (val colorGroup: ColorGroup) {
BOLUS (ColorGroup.InsulinTreatment),
@ -187,12 +186,4 @@ data class UserEntry(
Pump,
Aaps
}
fun isLoop(): Boolean {
var result = false
for (v in values) {
if (v.unit == Units.Source && Sources.fromString(v.sValue).equals(Sources.Loop)) result = true
}
return result
}
}

View file

@ -0,0 +1,51 @@
package info.nightscout.androidaps.database.serialisation
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import kotlin.jvm.internal.Reflection
import kotlin.reflect.KClass
object SealedClassHelper {
val gson: Gson = GsonBuilder().registerTypeAdapterFactory(
object : TypeAdapterFactory {
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
val kClass = Reflection.getOrCreateKotlinClass(type.rawType)
return if (kClass.sealedSubclasses.any()) {
SealedClassTypeAdapter(kClass, gson)
} else
gson.getDelegateAdapter(this, type)
}
}).create()
private class SealedClassTypeAdapter<T : Any>(private val kClass: KClass<Any>, val gson: Gson) : TypeAdapter<T>() {
override fun read(jsonReader: JsonReader): T? {
jsonReader.beginObject()
val nextName = jsonReader.nextName()
val innerClass = kClass.sealedSubclasses.firstOrNull { it.simpleName == nextName }
?: throw Exception("$nextName is not a child of the sealed class ${kClass.qualifiedName}")
val x = gson.fromJson<T>(jsonReader, innerClass.javaObjectType)
jsonReader.endObject()
// if there a static object, actually return that
return innerClass.objectInstance as T? ?: x
}
override fun write(out: JsonWriter, value: T) {
val jsonString = gson.toJson(value)
val name = value.javaClass.canonicalName
if (name != null) {
out.beginObject()
out.name(name.splitToSequence(".").last()).jsonValue(jsonString)
out.endObject()
}
}
}
}
inline fun <reified T> Gson.fromJson(json: String): T = fromJson(json, object : TypeToken<T>() {}.type)

View file

@ -2,19 +2,22 @@ package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.XXXValueWithUnit
class UserEntryTransaction(
val action: Action,
val s: String,
val values: MutableList<ValueWithUnit> = mutableListOf<ValueWithUnit>()
val source: Sources,
val note: String,
val values: List<XXXValueWithUnit?> = listOf()
) : Transaction<Unit>() {
override fun run() {
database.userEntryDao.insert(UserEntry(
timestamp = System.currentTimeMillis(),
action = action,
s = s,
source = source,
note = note,
values = values
))
}