carbs with duration

This commit is contained in:
Milos Kozak 2021-03-30 22:05:44 +02:00
parent 1ae4823a9a
commit 07d060c2b5
24 changed files with 2950 additions and 143 deletions

View file

@ -3,6 +3,8 @@ package info.nightscout.androidaps.dependencyInjection
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TherapyEventDataPoint
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
@Module

View file

@ -47,10 +47,10 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.source.DexcomPlugin
@ -778,7 +778,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (config.APS && lastRun?.constraintsProcessed != null) {
if (lastRun.constraintsProcessed!!.carbsReq > 0) {
//only display carbsreq when carbs have not been entered recently
val lastCarbsTime = repository.getLastBolusRecord()?.timestamp ?: 0L
val lastCarb = repository.getLastCarbsRecordWrapped().blockingGet()
val lastCarbsTime = if (lastCarb is ValueWrapper.Existing) lastCarb.value.timestamp else 0L
if (lastCarbsTime < lastRun.lastAPSRun) {
cobText = cobText + " | " + lastRun.constraintsProcessed!!.carbsReq + " " + resourceHelper.gs(R.string.required)
}
@ -862,7 +863,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// **** BG ****
if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions)
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions?.map { bg-> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }?.toMutableList())
else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
// Treatments

View file

@ -11,7 +11,8 @@ import com.jjoe64.graphview.series.Series
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.*
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.Bolus
@ -22,11 +23,7 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
@ -51,6 +48,7 @@ class GraphData(
@Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var translator: Translator
var maxY = Double.MIN_VALUE
private var minY = Double.MAX_VALUE
@ -77,7 +75,7 @@ class GraphData(
for (bg in bgReadingsArray!!) {
if (bg.timestamp < fromTime || bg.timestamp > toTime) continue
if (bg.value > maxBgValue) maxBgValue = bg.value
bgListArray.add(GlucoseValueDataPoint(injector, bg))
bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper))
}
if (predictions != null) {
predictions.sortWith(Comparator { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) })
@ -247,7 +245,7 @@ class GraphData(
it.y = getNearestBg(it.x.toLong())
filteredTreatments.add(it)
}
repository.getCarbsIncludingInvalidFromTimeToTime(fromTime, endTime, true).blockingGet()
repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet()
.map { CarbsDataPoint(it, resourceHelper) }
.forEach {
it.y = getNearestBg(it.x.toLong())
@ -273,7 +271,7 @@ class GraphData(
// Careportal
// databaseHelper.getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true)
repository.compatGetTherapyEventDataFromToTime(fromTime - T.hours(6).msecs(), endTime).blockingGet()
.map { TherapyEventDataPoint(injector, it) }
.map { TherapyEventDataPoint(it, resourceHelper, profileFunction, translator) }
.filterTimeframe(fromTime, endTime)
.forEach {
if (it.y == 0.0) it.y = getNearestBg(it.x.toLong())

View file

@ -1,12 +1,10 @@
package info.nightscout.androidaps.data
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
import android.graphics.Color
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
import info.nightscout.androidaps.utils.DecimalFormatter.toPumpSupportedBolus
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
@ -22,7 +20,7 @@ class BolusDataPoint @Inject constructor(
override fun getX(): Double = data.timestamp.toDouble()
override fun getY(): Double = if (data.type == Bolus.Type.SMB) defaultValueHelper.determineLowLine() else yValue
override fun getLabel(): String = toPumpSupportedBolus(data.amount, activePlugin.activePump, resourceHelper)
override fun getLabel(): String = DecimalFormatter.toPumpSupportedBolus(data.amount, activePlugin.activePump, resourceHelper)
override fun getDuration(): Long = 0
override fun getSize(): Float = 2f

View file

@ -1,9 +1,7 @@
package info.nightscout.androidaps.data
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
@ -20,7 +18,7 @@ class CarbsDataPoint @Inject constructor(
override fun getDuration(): Long = 0
override fun getSize(): Float = 2f
override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.BOLUS
override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.CARBS
override fun getColor(): Int =
if (data.isValid) resourceHelper.gc(R.color.carbs)

View file

@ -1,29 +1,20 @@
package info.nightscout.androidaps.data
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
class GlucoseValueDataPoint @Inject constructor(
val injector: HasAndroidInjector,
val data: GlucoseValue
val data: GlucoseValue,
private val defaultValueHelper: DefaultValueHelper,
private val profileFunction: ProfileFunction,
private val resourceHelper: ResourceHelper
) : DataPointWithLabelInterface {
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
init {
injector.androidInjector().inject(this)
}
fun valueToUnits(units: String): Double =
if (units == Constants.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL
@ -59,11 +50,11 @@ class GlucoseValueDataPoint @Inject constructor(
val predictionColor: Int
get() {
return when (data.sourceSensor) {
GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob)
GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob)
GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob)
GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob)
GlucoseValue.SourceSensor.aCOB_PREDICTION -> -0x7f000001 and resourceHelper.gc(R.color.cob)
GlucoseValue.SourceSensor.UAM_PREDICTION -> resourceHelper.gc(R.color.uam)
GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt)
GlucoseValue.SourceSensor.UAM_PREDICTION -> resourceHelper.gc(R.color.uam)
GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt)
else -> R.color.white
}
}

View file

@ -1,35 +1,25 @@
package info.nightscout.androidaps.data
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
import android.graphics.Color
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.interfaces.Interval
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
class TherapyEventDataPoint @Inject constructor(
val injector: HasAndroidInjector,
val data: TherapyEvent
val data: TherapyEvent,
private val resourceHelper: ResourceHelper,
private val profileFunction: ProfileFunction,
private val translator: Translator
) : DataPointWithLabelInterface, Interval {
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var translator: Translator
private var yValue = 0.0
init {
injector.androidInjector().inject(this)
}
override fun getX(): Double {
return data.timestamp.toDouble()
}

View file

@ -120,7 +120,7 @@ class UploadChunk @Inject constructor(
.forEach { bolus ->
result.add(BolusElement(bolus))
}
repository.getCarbsDataFromTimeToTime(start, end, true)
repository.getCarbsDataFromTimeToTimeExpanded(start, end, true)
.blockingGet()
.forEach { carb ->
result.add(WizardElement(carb))

View file

@ -24,6 +24,7 @@ import com.google.android.gms.wearable.WearableListenerService;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
@ -31,7 +32,7 @@ import dagger.android.AndroidInjection;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseValueDataPoint;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.database.AppRepository;
@ -530,12 +531,15 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
.stream()
.filter(bolus -> bolus.getType() != Bolus.Type.PRIMING)
.forEach(bolus -> boluses.add(treatmentMap(bolus.getTimestamp(), bolus.getAmount(), 0, bolus.getType() == Bolus.Type.SMB, bolus.isValid())));
repository.getCarbsIncludingInvalidFromTime(startTimeWindow, true).blockingGet()
repository.getCarbsDataFromTimeExpanded(startTimeWindow, true).blockingGet()
.forEach(carb -> boluses.add(treatmentMap(carb.getTimestamp(), 0, carb.getAmount(), false, carb.isValid())));
final LoopPlugin.LastRun finalLastRun = loopPlugin.getLastRun();
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().getHasPredictions() && finalLastRun.getConstraintsProcessed() != null) {
List<GlucoseValueDataPoint> predArray = finalLastRun.getConstraintsProcessed().getPredictions();
List<GlucoseValueDataPoint> predArray =
finalLastRun.getConstraintsProcessed().getPredictions()
.stream().map( bg -> new GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper))
.collect(Collectors.toList());
if (!predArray.isEmpty()) {
final String units = profileFunction.getUnits();

View file

@ -28,7 +28,6 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.expandCarbs
import info.nightscout.androidaps.utils.extensions.iobCalc
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@ -532,8 +531,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
var displayCob: Double? = null
var futureCarbs = 0.0
val now = DateUtil.now()
val carbs = repository.getCarbsDataFromTime(now, true)
.blockingGet()
val carbs = repository.getCarbsDataFromTimeExpanded(now, true).blockingGet()
if (autosensData != null) {
displayCob = autosensData.cob
carbs.forEach { carb ->
@ -603,8 +601,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME)
}
val absorptionTimeAgo = now - (maxAbsorptionHours * T.hours(1).msecs()).toLong()
repository.getCarbsDataFromTimeToTime(absorptionTimeAgo + 1, now, true)
.map { it.map { c -> c.expandCarbs() }.flatten() }
repository.getCarbsDataFromTimeToTimeExpanded(absorptionTimeAgo + 1, now, true)
.blockingGet()
.forEach {
if (it.amount > 0) {

View file

@ -189,7 +189,7 @@ class IobCobOref1Thread internal constructor(
aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null")
}
}
val recentCarbTreatments = repository.getCarbsDataFromTimeToTime(bgTime - T.mins(5).msecs(), bgTime, true).blockingGet()
val recentCarbTreatments = repository.getCarbsDataFromTimeToTimeExpanded(bgTime - T.mins(5).msecs(), bgTime, true).blockingGet()
for (recentCarbTreatment in recentCarbTreatments) {
autosensData.carbsFromBolus += recentCarbTreatment.amount
val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()

View file

@ -188,7 +188,7 @@ class IobCobThread @Inject internal constructor(
aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null")
}
}
val recentCarbTreatments = repository.getCarbsDataFromTimeToTime(bgTime - T.mins(5).msecs(), bgTime, true).blockingGet()
val recentCarbTreatments = repository.getCarbsDataFromTimeToTimeExpanded(bgTime - T.mins(5).msecs(), bgTime, true).blockingGet()
for (recentCarbTreatment in recentCarbTreatments) {
autosensData.carbsFromBolus += recentCarbTreatment.amount
val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()

View file

@ -293,7 +293,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
ml.carbs?.let { carbs ->
holder.binding.carbsDate.text = dateUtil.timeString(carbs.timestamp)
holder.binding.carbs.text = resourceHelper.gs(R.string.format_carbs, carbs.amount.toInt())
holder.binding.carbsDuration.text = resourceHelper.gs(R.string.format_mins, T.msecs(carbs.duration).mins().toInt())
holder.binding.carbsDuration.text = if (carbs.duration> 0) resourceHelper.gs(R.string.format_mins, T.msecs(carbs.duration).mins().toInt()) else ""
holder.binding.carbsNs.visibility = (NSUpload.isIdValid(carbs.interfaceIDs.nightscoutId)).toVisibility()
holder.binding.carbsPump.visibility = (carbs.interfaceIDs.pumpId != null).toVisibility()
holder.binding.carbsInvalid.visibility = carbs.isValid.not().toVisibility()

View file

@ -65,7 +65,7 @@ class TddCalculator @Inject constructor(
tdd.bolus += t.amount
result.put(midnight, tdd)
}
repository.getCarbsDataFromTimeToTime(startTime, endTime, true).blockingGet().forEach { t->
repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t->
val midnight = MidnightTime.calc(t.timestamp)
val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0)
tdd.carbs += t.amount

View file

@ -205,6 +205,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:textStyle="bold" />
<TextView

View file

@ -2,10 +2,8 @@ package info.nightscout.androidaps.core.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.data.TherapyEventDataPoint
import info.nightscout.androidaps.db.ExtendedBolus
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.TemporaryBasal
@ -31,6 +29,4 @@ abstract class CoreDataClassesModule {
@ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch
@ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal
@ContributesAndroidInjector abstract fun extendedBolusInjector(): ExtendedBolus
@ContributesAndroidInjector abstract fun glucoseValueDataPointInjector(): GlucoseValueDataPoint
@ContributesAndroidInjector abstract fun therapyEventDataPointInjector(): TherapyEventDataPoint
}

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.aps.loop
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -185,9 +184,9 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
return json
}
val predictions: MutableList<GlucoseValueDataPoint>
val predictions: MutableList<GlucoseValue>
get() {
val array: MutableList<GlucoseValueDataPoint> = ArrayList()
val array: MutableList<GlucoseValue> = ArrayList()
val startTime = date
json?.let { json ->
if (json.has("predBGs")) {
@ -203,7 +202,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
sourceSensor = GlucoseValue.SourceSensor.IOB_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
array.add(gv)
}
}
if (predBGs.has("aCOB")) {
@ -217,7 +216,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
sourceSensor = GlucoseValue.SourceSensor.aCOB_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
array.add(gv)
}
}
if (predBGs.has("COB")) {
@ -231,7 +230,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
sourceSensor = GlucoseValue.SourceSensor.COB_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
array.add(gv)
}
}
if (predBGs.has("UAM")) {
@ -245,7 +244,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
sourceSensor = GlucoseValue.SourceSensor.UAM_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
array.add(gv)
}
}
if (predBGs.has("ZT")) {
@ -259,7 +258,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
sourceSensor = GlucoseValue.SourceSensor.ZT_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
array.add(gv)
}
}
}

View file

@ -18,15 +18,12 @@ package info.nightscout.androidaps.plugins.general.overview.graphExtensions;
* You should have received a copy of the GNU General Public License
* with the "Linking Exception" along with this program; if not,
* write to the author Jonas Gehring <g.jjoe64@gmail.com>.
* <p>
*/
/*
* Added by mike
*/
/**
* Added by mike
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
@ -61,6 +58,7 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
TRIANGLE,
RECTANGLE,
BOLUS,
CARBS,
SMB,
EXTENDEDBOLUS,
PROFILE,
@ -233,7 +231,18 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawArrows(points, canvas, mPaint);
if (value.getLabel() != null) {
drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
}
} else if (value.getShape() == Shape.CARBS) {
mPaint.setStrokeWidth(0);
Point[] points = new Point[3];
points[0] = new Point((int) endX, (int) (endY - scaledPxSize));
points[1] = new Point((int) (endX + scaledPxSize), (int) (endY + scaledPxSize * 0.67));
points[2] = new Point((int) (endX - scaledPxSize), (int) (endY + scaledPxSize * 0.67));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawArrows(points, canvas, mPaint);
if (value.getLabel() != null) {
drawLabel45Left(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
}
} else if (value.getShape() == Shape.SMB) {
mPaint.setStrokeWidth(2);
@ -282,21 +291,21 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
mPaint.setStrokeWidth(0);
canvas.drawCircle(endX, endY, scaledPxSize, mPaint);
if (value.getLabel() != null) {
drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
}
} else if (value.getShape() == Shape.ANNOUNCEMENT) {
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeWidth(0);
canvas.drawCircle(endX, endY, scaledPxSize, mPaint);
if (value.getLabel() != null) {
drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
}
} else if (value.getShape() == Shape.GENERAL) {
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeWidth(0);
canvas.drawCircle(endX, endY, scaledPxSize, mPaint);
if (value.getLabel() != null) {
drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize);
}
} else if (value.getShape() == Shape.EXERCISE) {
mPaint.setStrokeWidth(0);
@ -380,29 +389,29 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
canvas.restore();
}
void drawLabel45(float endX, float endY, E value, Canvas canvas, Float scaledPxSize, Float scaledTextSize) {
if (value.getLabel().startsWith("~")) {
float px = endX;
float py = endY + scaledPxSize;
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((float) (scaledTextSize * 0.8));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
mPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(value.getLabel().substring(1), px - scaledPxSize, py, mPaint);
mPaint.setTextAlign(Paint.Align.LEFT);
canvas.restore();
} else {
float px = endX;
float py = endY - scaledPxSize;
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((float) (scaledTextSize * 0.8));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + scaledPxSize, py, mPaint);
canvas.restore();
}
void drawLabel45Right(float endX, float endY, E value, Canvas canvas, Float scaledPxSize, Float scaledTextSize) {
float px = endX;
float py = endY - scaledPxSize;
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((float) (scaledTextSize * 0.8));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + scaledPxSize, py, mPaint);
canvas.restore();
}
}
void drawLabel45Left(float endX, float endY, E value, Canvas canvas, Float scaledPxSize, Float scaledTextSize) {
float px = endX;
float py = endY + scaledPxSize;
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((float) (scaledTextSize * 0.8));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
mPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(value.getLabel(), px - scaledPxSize, py, mPaint);
mPaint.setTextAlign(Paint.Align.LEFT);
canvas.restore();
}
}

View file

@ -5,31 +5,7 @@ import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T
import org.json.JSONObject
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
fun Carbs.expandCarbs(): List<Carbs> =
mutableListOf<Carbs>().also { carbs ->
if (this.duration == 0L) {
carbs.add(this)
} else {
var remainingCarbs = this.amount
val ticks = T.msecs(this.duration).hours() * 4 //duration guaranteed to be integer greater zero
for (i in 0 until ticks) {
val carbTime = this.timestamp + i * 15 * 60 * 1000
val smallCarbAmount = (1.0 * remainingCarbs / (ticks - i)).roundToInt() //on last iteration (ticks-i) is 1 -> smallCarbAmount == remainingCarbs
remainingCarbs -= smallCarbAmount.toLong()
if (smallCarbAmount > 0)
carbs.add(Carbs(
timestamp = carbTime,
amount = smallCarbAmount.toDouble(),
duration = 0
))
}
}
}
fun Carbs.toJson(): JSONObject =
JSONObject()

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@ import io.reactivex.subjects.PublishSubject
import java.util.concurrent.Callable
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.roundToInt
@Singleton
open class AppRepository @Inject internal constructor(
@ -310,6 +311,27 @@ open class AppRepository @Inject internal constructor(
database.bolusDao.deleteAllEntries()
// CARBS
val timeBackForExpand = 8 * 60 * 60 * 1000
private fun expandCarbs(carbs: Carbs): List<Carbs> =
if (carbs.duration == 0L) {
listOf(carbs)
} else {
var remainingCarbs = carbs.amount
val ticks = (carbs.duration / 1000 / 60 / 15).coerceAtLeast(1L)
(0 until ticks).map {
val carbTime = carbs.timestamp + it * 15 * 60 * 1000
val smallCarbAmount = (1.0 * remainingCarbs / (ticks - it)).roundToInt() //on last iteration (ticks-i) is 1 -> smallCarbAmount == remainingCarbs
remainingCarbs -= smallCarbAmount.toLong()
Carbs(timestamp = carbTime, amount = smallCarbAmount.toDouble(), duration = 0)
}.filter { it.amount != 0.0 }
}
private fun Single<List<Carbs>>.expand() = this.map { it.map(::expandCarbs).flatten() }
private fun Single<List<Carbs>>.filterOutExtended() = this.map { it.filter { c -> c.duration == 0L } }
private fun Single<List<Carbs>>.fromTo(from: Long, to: Long) = this.map { it.filter { c -> c.timestamp in from..to } }
private fun Single<List<Carbs>>.sort() = this.map { it.sortedBy { c -> c.timestamp } }
/*
* returns a Pair of the next entity to sync and the ID of the "update".
* The update id might either be the entry id itself if it is a new entry - or the id
@ -339,6 +361,11 @@ open class AppRepository @Inject internal constructor(
fun getLastCarbsRecord(): Carbs? =
database.carbsDao.getLastCarbsRecord()
fun getLastCarbsRecordWrapped(): Single<ValueWrapper<Carbs>> =
database.carbsDao.getLastCarbsRecordMaybe()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
fun getOldestCarbsRecord(): Carbs? =
database.carbsDao.getOldestCarbsRecord()
@ -347,18 +374,35 @@ open class AppRepository @Inject internal constructor(
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getCarbsDataFromTimeExpanded(timestamp: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsFromTime(timestamp - timeBackForExpand)
.expand()
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getCarbsDataFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsFromTimeToTime(from, to)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getCarbsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTime(timestamp)
fun getCarbsDataFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsFromTimeToTime(from - timeBackForExpand, to)
.expand()
.fromTo(from, to)
.sort()
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getCarbsIncludingInvalidFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTimeToTime(from, to)
fun getCarbsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTime(timestamp - timeBackForExpand)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getCarbsIncludingInvalidFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single<List<Carbs>> =
database.carbsDao.getCarbsIncludingInvalidFromTimeToTime(from - timeBackForExpand, to)
.expand()
.fromTo(from, to)
.sort()
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())

View file

@ -26,6 +26,9 @@ internal interface CarbsDao : TraceableDao<Carbs> {
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC LIMIT 1")
fun getLastCarbsRecord(): Carbs?
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC LIMIT 1")
fun getLastCarbsRecordMaybe(): Maybe<Carbs>
@Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id ASC LIMIT 1")
fun getOldestCarbsRecord(): Carbs?