Profile comparator

This commit is contained in:
Milos Kozak 2020-07-06 13:52:10 +02:00
parent ceaa3c8750
commit b91f8e668a
5 changed files with 180 additions and 27 deletions

View file

@ -8,9 +8,9 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.defaultProfile.DefaultProfile
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.ActivityMonitor
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.InstanceId
@ -62,16 +62,19 @@ class SurveyActivity : NoSplashAppCompatActivity() {
ToastUtils.showToastInUiThread(this, R.string.invalidweight)
return@setOnClickListener
}
val profile = defaultProfile.profile(age, tdd, weight, profileFunction.getUnits())
val args = Bundle()
args.putLong("time", DateUtil.now())
args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal)
args.putString("customProfile", profile.data.toString())
args.putString("customProfileUnits", profile.units)
args.putString("customProfileName", "Age: $age TDD: $tdd Weight: $weight")
val pvd = ProfileViewerDialog()
pvd.arguments = args
pvd.show(supportFragmentManager, "ProfileViewDialog")
profileFunction.getProfile()?.let { runningProfile ->
val profile = defaultProfile.profile(age, tdd, weight, profileFunction.getUnits())
ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now())
it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal)
it.putString("customProfile", runningProfile.data.toString())
it.putString("customProfile2", profile.data.toString())
it.putString("customProfileUnits", profile.units)
it.putString("customProfileName", "Age: $age TDD: $tdd Weight: $weight")
}
}.show(supportFragmentManager, "ProfileViewDialog")
}
}
survey_submit.setOnClickListener {

View file

@ -370,7 +370,7 @@ public class Profile {
return lastValue;
}
protected String format_HH_MM(Integer timeAsSeconds) {
public static String format_HH_MM(Integer timeAsSeconds) {
String time;
int hour = timeAsSeconds / 60 / 60;
int minutes = (timeAsSeconds - hour * 60 * 60) / 60;

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.dialogs
import android.os.Bundle
import android.text.Spanned
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -14,10 +15,12 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.close.*
import kotlinx.android.synthetic.main.dialog_profileviewer.*
import org.json.JSONObject
import java.text.DecimalFormat
import javax.inject.Inject
class ProfileViewerDialog : DaggerDialogFragment() {
@ -32,11 +35,13 @@ class ProfileViewerDialog : DaggerDialogFragment() {
enum class Mode(val i: Int) {
RUNNING_PROFILE(1),
CUSTOM_PROFILE(2),
DB_PROFILE(3)
DB_PROFILE(3),
PROFILE_COMPARE(4)
}
private var mode: Mode = Mode.RUNNING_PROFILE
private var customProfileJson: String = ""
private var customProfileJson2: String = ""
private var customProfileName: String = ""
private var customProfileUnits: String = Constants.MGDL
@ -49,6 +54,8 @@ class ProfileViewerDialog : DaggerDialogFragment() {
customProfileJson = bundle.getString("customProfile", "")
customProfileUnits = bundle.getString("customProfileUnits", Constants.MGDL)
customProfileName = bundle.getString("customProfileName", "")
if (mode == Mode.PROFILE_COMPARE)
customProfileJson2 = bundle.getString("customProfile2", "")
}
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
@ -65,11 +72,13 @@ class ProfileViewerDialog : DaggerDialogFragment() {
close.setOnClickListener { dismiss() }
val profile: Profile?
val profile2: Profile?
val profileName: String?
val date: String?
when (mode) {
Mode.RUNNING_PROFILE -> {
profile = activePlugin.activeTreatments.getProfileSwitchFromHistory(time)?.profileObject
profile2 = null
profileName = activePlugin.activeTreatments.getProfileSwitchFromHistory(time)?.customizedName
date = dateUtil.dateAndTimeString(activePlugin.activeTreatments.getProfileSwitchFromHistory(time)?.date
?: 0)
@ -78,6 +87,15 @@ class ProfileViewerDialog : DaggerDialogFragment() {
Mode.CUSTOM_PROFILE -> {
profile = Profile(injector, JSONObject(customProfileJson), customProfileUnits)
profile2 = null
profileName = customProfileName
date = ""
profileview_datelayout.visibility = View.GONE
}
Mode.PROFILE_COMPARE -> {
profile = Profile(injector, JSONObject(customProfileJson), customProfileUnits)
profile2 = Profile(injector, JSONObject(customProfileJson2), customProfileUnits)
profileName = customProfileName
date = ""
profileview_datelayout.visibility = View.GONE
@ -86,6 +104,7 @@ class ProfileViewerDialog : DaggerDialogFragment() {
Mode.DB_PROFILE -> {
val profileList = databaseHelper.getProfileSwitchData(time, true)
profile = if (profileList.isNotEmpty()) profileList[0].profileObject else null
profile2 = null
profileName = if (profileList.isNotEmpty()) profileList[0].customizedName else null
date = if (profileList.isNotEmpty()) dateUtil.dateAndTimeString(profileList[0].date) else null
profileview_datelayout.visibility = View.VISIBLE
@ -93,20 +112,38 @@ class ProfileViewerDialog : DaggerDialogFragment() {
}
profileview_noprofile.visibility = View.VISIBLE
profile?.let {
profileview_units.text = it.units
profileview_dia.text = resourceHelper.gs(R.string.format_hours, it.dia)
profileview_activeprofile.text = profileName
profileview_date.text = date
profileview_ic.text = it.icList
profileview_isf.text = it.isfList
profileview_basal.text = it.basalList
profileview_target.text = it.targetList
basal_graph.show(it)
if (mode == Mode.PROFILE_COMPARE)
profile?.let { profile1 ->
profile2?.let { profile2 ->
profileview_units.text = profile1.units
profileview_dia.text = HtmlHelper.fromHtml(formatColors("", profile1.dia, profile1.dia, DecimalFormat("0.00"), resourceHelper.gs(R.string.shorthour)))
profileview_activeprofile.text = profileName
profileview_date.text = date
profileview_ic.text = ics(profile1, profile2)
profileview_isf.text = isfs(profile1, profile2)
profileview_basal.text = basals(profile1, profile2)
profileview_target.text = HtmlHelper.fromHtml(formatColors("", profile1.targetList + "<br>", profile2.targetList, ""))
basal_graph.show(profile1, profile2)
}
profileview_noprofile.visibility = View.GONE
profileview_invalidprofile.visibility = if (it.isValid("ProfileViewDialog")) View.GONE else View.VISIBLE
}
profileview_noprofile.visibility = View.GONE
profileview_invalidprofile.visibility = if (profile1.isValid("ProfileViewDialog")) View.GONE else View.VISIBLE
}
else
profile?.let {
profileview_units.text = it.units
profileview_dia.text = resourceHelper.gs(R.string.format_hours, it.dia)
profileview_activeprofile.text = profileName
profileview_date.text = date
profileview_ic.text = it.icList
profileview_isf.text = it.isfList
profileview_basal.text = it.basalList
profileview_target.text = it.targetList
basal_graph.show(it)
profileview_noprofile.visibility = View.GONE
profileview_invalidprofile.visibility = if (it.isValid("ProfileViewDialog")) View.GONE else View.VISIBLE
}
}
override fun onStart() {
@ -121,6 +158,79 @@ class ProfileViewerDialog : DaggerDialogFragment() {
bundle.putString("customProfile", customProfileJson)
bundle.putString("customProfileName", customProfileName)
bundle.putString("customProfileUnits", customProfileUnits)
if (mode == Mode.PROFILE_COMPARE)
bundle.putString("customProfile2", customProfileJson2)
}
private fun formatColors(label: String, value1: Double, value2: Double, format: DecimalFormat, units: String): String {
return formatColors(label, format.format(value1), format.format(value2), units)
}
private fun formatColors(label: String, text1: String, text2: String, units: String): String {
var s = "<font color='${resourceHelper.gc(R.color.white)}'>$label</font>"
s += " "
s += "<font color='${resourceHelper.gc(R.color.tempbasal)}'>$text1</font>"
s += " "
s += "<font color='${resourceHelper.gc(R.color.examinedProfile)}'>$text2</font>"
s += " "
s += "<font color='${resourceHelper.gc(R.color.white)}'>$units</font>"
return s
}
private fun basals(profile1: Profile, profile2: Profile): Spanned {
var prev1 = 0.0
var prev2 = 0.0
val s = StringBuilder()
for (hour in 0..23) {
val val1 = profile1.getBasalTimeFromMidnight(hour * 60 * 60)
val val2 = profile2.getBasalTimeFromMidnight(hour * 60 * 60)
if (val1 != prev1 || val2 != prev2) {
s.append(formatColors(Profile.format_HH_MM(hour * 60 * 60), val1, val2, DecimalFormat("0.00"), resourceHelper.gs(R.string.profile_ins_units_per_hour)))
s.append("<br>")
}
prev1 = val1
prev2 = val2
}
s.append(formatColors(
"",
profile1.baseBasalSum(),
profile2.baseBasalSum(),
DecimalFormat("0.00"),
resourceHelper.gs(R.string.insulin_unit_shortname)))
return HtmlHelper.fromHtml(s.toString())
}
private fun ics(profile1: Profile, profile2: Profile): Spanned {
var prev1 = 0.0
var prev2 = 0.0
val s = StringBuilder()
for (hour in 0..23) {
val val1 = profile1.getIcTimeFromMidnight(hour * 60 * 60)
val val2 = profile2.getIcTimeFromMidnight(hour * 60 * 60)
if (val1 != prev1 || val2 != prev2) {
s.append(formatColors(Profile.format_HH_MM(hour * 60 * 60), val1, val2, DecimalFormat("0.0"), resourceHelper.gs(R.string.profile_carbs_per_unit)))
s.append("<br>")
}
prev1 = val1
prev2 = val2
}
return HtmlHelper.fromHtml(s.toString())
}
private fun isfs(profile1: Profile, profile2: Profile): Spanned {
var prev1 = 0.0
var prev2 = 0.0
val s = StringBuilder()
for (hour in 0..23) {
val val1 = Profile.fromMgdlToUnits(profile1.getIsfMgdlTimeFromMidnight(hour * 60 * 60), profile1.units)
val val2 = Profile.fromMgdlToUnits(profile2.getIsfMgdlTimeFromMidnight(hour * 60 * 60), profile1.units)
if (val1 != prev1 || val2 != prev2) {
s.append(formatColors(Profile.format_HH_MM(hour * 60 * 60), val1, val2, DecimalFormat("0.0"), resourceHelper.gs(R.string.profile_carbs_per_unit)))
s.append("<br>")
}
prev1 = val1
prev2 = val2
}
return HtmlHelper.fromHtml(s.toString())
}
}

View file

@ -1,13 +1,16 @@
package info.nightscout.androidaps.plugins.treatments.fragments
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import com.jjoe64.graphview.GraphView
import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.utils.Round
import java.util.*
import kotlin.math.max
class ProfileGraph : GraphView {
@ -21,7 +24,7 @@ class ProfileGraph : GraphView {
basalArray.add(DataPoint(hour.toDouble(), profile.getBasalTimeFromMidnight(hour * 60 * 60)))
basalArray.add(DataPoint((hour + 1).toDouble(), profile.getBasalTimeFromMidnight(hour * 60 * 60)))
}
val basalDataPoints: Array<DataPoint> = Array(basalArray.size){ i-> basalArray[i]}
val basalDataPoints: Array<DataPoint> = Array(basalArray.size) { i -> basalArray[i] }
val basalSeries: LineGraphSeries<DataPoint> = LineGraphSeries(basalDataPoints)
addSeries(basalSeries)
basalSeries.thickness = 8
@ -35,4 +38,40 @@ class ProfileGraph : GraphView {
gridLabelRenderer.numHorizontalLabels = 13
gridLabelRenderer.verticalLabelsColor = basalSeries.color
}
fun show(profile1: Profile, profile2: Profile) {
removeAllSeries()
// profile 1
val basalArray1: MutableList<DataPoint> = ArrayList()
for (hour in 0..23) {
basalArray1.add(DataPoint(hour.toDouble(), profile1.getBasalTimeFromMidnight(hour * 60 * 60)))
basalArray1.add(DataPoint((hour + 1).toDouble(), profile1.getBasalTimeFromMidnight(hour * 60 * 60)))
}
val basalSeries1: LineGraphSeries<DataPoint> = LineGraphSeries(Array(basalArray1.size) { i -> basalArray1[i] })
addSeries(basalSeries1)
basalSeries1.thickness = 8
basalSeries1.isDrawBackground = true
// profile 2
val basalArray2: MutableList<DataPoint> = ArrayList()
for (hour in 0..23) {
basalArray2.add(DataPoint(hour.toDouble(), profile2.getBasalTimeFromMidnight(hour * 60 * 60)))
basalArray2.add(DataPoint((hour + 1).toDouble(), profile2.getBasalTimeFromMidnight(hour * 60 * 60)))
}
val basalSeries2: LineGraphSeries<DataPoint> = LineGraphSeries(Array(basalArray2.size) { i -> basalArray2[i] })
addSeries(basalSeries2)
basalSeries2.thickness = 8
basalSeries2.isDrawBackground = false
basalSeries2.color = context.getColor(R.color.examinedProfile)
basalSeries2.backgroundColor = context.getColor(R.color.examinedProfile)
viewport.isXAxisBoundsManual = true
viewport.setMinX(0.0)
viewport.setMaxX(24.0)
viewport.isYAxisBoundsManual = true
viewport.setMinY(0.0)
viewport.setMaxY(Round.ceilTo(max(profile1.maxDailyBasal, profile2.maxDailyBasal) * 1.1, 0.5))
gridLabelRenderer.numHorizontalLabels = 13
}
}

View file

@ -23,6 +23,7 @@
<color name="warningAlertHeaderText">#FF000000</color>
<color name="errorAlertBackground">#FFFF5555</color>
<color name="errorAlertHeaderText">#FF000000</color>
<color name="examinedProfile">#FFFF5555</color>
<!-- Treatment-->
<color name="tempbasal">#C803A9F4</color>