diff --git a/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt index 3fc64254a2..a7b6864b8a 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt @@ -7,6 +7,7 @@ import android.text.Editable import android.text.TextWatcher import android.view.Menu import android.widget.PopupMenu +import android.widget.TextView import info.nightscout.androidaps.R import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.PureProfile @@ -66,6 +67,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { private lateinit var binding: ActivityProfilehelperBinding + @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityProfilehelperBinding.inflate(layoutInflater) @@ -78,11 +80,11 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { switchTab(1, typeSelected[1]) } - binding.profiletype.setOnClickListener { - PopupMenu(this, binding.profiletype).apply { + binding.profileType.setOnClickListener { + PopupMenu(this, binding.profileType).apply { menuInflater.inflate(R.menu.menu_profilehelper, menu) setOnMenuItemClickListener { item -> - binding.profiletype.setText(item.title) + binding.profileType.setText(item.title) when (item.itemId) { R.id.menu_default -> switchTab(tabSelected, ProfileType.MOTOL_DEFAULT) R.id.menu_default_dpv -> switchTab(tabSelected, ProfileType.DPV_DEFAULT) @@ -129,7 +131,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { } // Default profile - binding.copytolocalprofile.setOnClickListener { + binding.copyToLocalProfile.setOnClickListener { storeValues() val age = ageUsed[tabSelected] val weight = weightUsed[tabSelected] @@ -167,20 +169,22 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { } }) - binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null) + binding.basalPctFromTdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null) - @SuppressLint("SetTextI18n") - binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) + binding.tdds.addView(TextView(this).apply { text = rh.gs(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) }) Thread { - val tdds = tddCalculator.stats() - runOnUiThread { binding.tdds.text = tdds } + val tdds = tddCalculator.stats(this) + runOnUiThread { + binding.tdds.removeAllViews() + binding.tdds.addView(tdds) + } }.start() // Current profile binding.currentProfileText.text = profileFunction.getProfileName() // General - binding.compareprofile.setOnClickListener { + binding.compareProfiles.setOnClickListener { storeValues() for (i in 0..1) { if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) { @@ -241,7 +245,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { binding.age.editText?.id?.let { binding.ageLabel.labelFor = it } binding.tdd.editText?.id?.let { binding.tddLabel.labelFor = it } binding.weight.editText?.id?.let { binding.weightLabel.labelFor = it } - binding.basalpctfromtdd.editText?.id?.let { binding.basalpctfromtddLabel.labelFor = it } + binding.basalPctFromTdd.editText?.id?.let { binding.basalPctFromTddLabel.labelFor = it } switchTab(0, typeSelected[0], false) } @@ -272,7 +276,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { ageUsed[tabSelected] = binding.age.value weightUsed[tabSelected] = binding.weight.value tddUsed[tabSelected] = binding.tdd.value - pctUsed[tabSelected] = binding.basalpctfromtdd.value + pctUsed[tabSelected] = binding.basalPctFromTdd.value } private fun switchTab(tab: Int, newContent: ProfileType, storeOld: Boolean = true) { @@ -282,10 +286,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { tabSelected = tab typeSelected[tabSelected] = newContent - binding.profiletypeTitle.defaultHintTextColor = ColorStateList.valueOf(rh.gc(if (tab == 0) R.color.helperProfile else R.color.examinedProfile)) + binding.profileTypeTitle.defaultHintTextColor = ColorStateList.valueOf(rh.gc(if (tab == 0) R.color.helperProfile else R.color.examinedProfile)) // show new content - binding.profiletype.setText( + binding.profileType.setText( when (typeSelected[tabSelected]) { ProfileType.MOTOL_DEFAULT -> rh.gs(R.string.motoldefaultprofile) ProfileType.DPV_DEFAULT -> rh.gs(R.string.dpvdefaultprofile) @@ -303,9 +307,9 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { binding.age.value = ageUsed[tabSelected] binding.weight.value = weightUsed[tabSelected] binding.tdd.value = tddUsed[tabSelected] - binding.basalpctfromtdd.value = pctUsed[tabSelected] + binding.basalPctFromTdd.value = pctUsed[tabSelected] - binding.basalpctfromtddRow.visibility = (newContent == ProfileType.DPV_DEFAULT).toVisibility() + binding.basalPctFromTddRow.visibility = (newContent == ProfileType.DPV_DEFAULT).toVisibility() if (profileList.isNotEmpty()) binding.availableProfileList.setText(profileList[profileUsed[tabSelected]].toString()) if (profileSwitch.isNotEmpty()) diff --git a/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt index 1ad4bb826f..39842724cb 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.activities import android.annotation.SuppressLint import android.os.Bundle +import android.widget.TextView import info.nightscout.androidaps.R import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Sources @@ -9,7 +10,6 @@ import info.nightscout.androidaps.databinding.ActivityStatsBinding import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.utils.ActivityMonitor import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.androidaps.utils.stats.TirCalculator import javax.inject.Inject @@ -29,21 +29,30 @@ class StatsActivity : NoSplashAppCompatActivity() { binding = ActivityStatsBinding.inflate(layoutInflater) setContentView(binding.root) - binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) - binding.tir.text = getString(R.string.tir) + ": " + rh.gs(R.string.calculation_in_progress) - binding.activity.text = rh.gs(R.string.activitymonitor) + ": " + rh.gs(R.string.calculation_in_progress) + binding.tdds.addView(TextView(this).apply { text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) }) + binding.tir.addView(TextView(this).apply { text = getString(R.string.tir) + ": " + rh.gs(R.string.calculation_in_progress) }) + binding.activity.addView(TextView(this).apply { text = getString(R.string.activitymonitor) + ": " + rh.gs(R.string.calculation_in_progress) }) Thread { - val tdds = tddCalculator.stats() - runOnUiThread { binding.tdds.text = tdds } + val tdds = tddCalculator.stats(this) + runOnUiThread { + binding.tdds.removeAllViews() + binding.tdds.addView(tdds) + } }.start() Thread { - val tir = tirCalculator.stats() - runOnUiThread { binding.tir.text = tir } + val tir = tirCalculator.stats(this) + runOnUiThread { + binding.tir.removeAllViews() + binding.tir.addView(tir) + } }.start() Thread { - val activity = activityMonitor.stats() - runOnUiThread { binding.activity.text = activity } + val activity = activityMonitor.stats(this) + runOnUiThread { + binding.activity.removeAllViews() + binding.activity.addView(activity) + } }.start() binding.ok.setOnClickListener { finish() } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt index a147e26ea2..88dfaf97fe 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt @@ -43,9 +43,9 @@ class SurveyActivity : NoSplashAppCompatActivity() { val profileList = profileStore?.getProfileList() ?: return binding.spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList) - binding.tdds.text = tddCalculator.stats() - binding.tir.text = tirCalculator.stats() - binding.activity.text = activityMonitor.stats() + //binding.tdds.text = tddCalculator.stats() + //binding.tir.text = tirCalculator.stats() + //binding.activity.text = activityMonitor.stats() binding.profile.setOnClickListener { val age = SafeParse.stringToDouble(binding.age.text.toString()) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt b/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt index 480bc30aa2..f1352441b4 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt @@ -2,14 +2,20 @@ package info.nightscout.androidaps.utils import android.app.Activity import android.app.Application +import android.content.Context +import android.graphics.Typeface import android.os.Bundle -import android.text.Spanned +import android.view.Gravity +import android.view.ViewGroup +import android.widget.TableLayout +import android.widget.TableRow +import android.widget.TextView import info.nightscout.androidaps.R +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.shared.SafeParse import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag -import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.shared.sharedPreferences.SP -import info.nightscout.shared.SafeParse import javax.inject.Inject import javax.inject.Singleton @@ -58,24 +64,47 @@ class ActivityMonitor @Inject constructor( override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { } - private fun toText(): String { - val keys: Map = sp.getAll() - var result = "" - for ((key, value) in keys) - if (key.startsWith("Monitor") && key.endsWith("total")) { - val v = if (value is Long) value else SafeParse.stringToLong(value as String) - val activity = key.split("_")[1].replace("Activity", "") - val duration = dateUtil.niceTimeScalar(v, rh) - val start = sp.getLong(key.replace("total", "start"), 0) - val days = T.msecs(dateUtil.now() - start).days() - result += rh.gs(R.string.activitymonitorformat, activity, duration, days) - } - return result - } + fun stats(context: Context): TableLayout = + TableLayout(context).also { layout -> + layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) + layout.addView( + TextView(context).apply { + text = rh.gs(R.string.activitymonitor) + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + setTextAppearance(android.R.style.TextAppearance_Material_Medium) + }) + layout.addView( + TableRow(context).also { row -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f } + row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + row.gravity = Gravity.CENTER_HORIZONTAL + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 0 }; text = rh.gs(R.string.activity) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 1 }; text = rh.gs(R.string.duration) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 2 } }) + } + ) - fun stats(): Spanned { - return HtmlHelper.fromHtml("
" + rh.gs(R.string.activitymonitor) + ":
" + toText()) - } + val keys: Map = sp.getAll() + for ((key, value) in keys) + if (key.startsWith("Monitor") && key.endsWith("total")) { + val v = if (value is Long) value else SafeParse.stringToLong(value as String) + val activity = key.split("_")[1].replace("Activity", "") + val duration = dateUtil.niceTimeScalar(v, rh) + val start = sp.getLong(key.replace("total", "start"), 0) + val days = T.msecs(dateUtil.now() - start).days() + layout.addView( + TableRow(context).also { row -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f } + row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + row.gravity = Gravity.CENTER_HORIZONTAL + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 0 }; text = activity }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 1 }; text = duration }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 2 }; text = rh.gs(R.string.in_days, days.toDouble()) }) + } + ) + } + } fun reset() { val keys: Map = sp.getAll() diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TIR.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TIR.kt index 6b688c15cb..f0fa7d8e7c 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TIR.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TIR.kt @@ -1,11 +1,16 @@ package info.nightscout.androidaps.utils.stats +import android.annotation.SuppressLint +import android.content.Context +import android.view.Gravity +import android.widget.TableRow +import android.widget.TextView import info.nightscout.androidaps.R import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper -import kotlin.math.roundToInt class TIR(val date: Long, val lowThreshold: Double, val highThreshold: Double) { + internal var below = 0 internal var inRange = 0 internal var above = 0 @@ -17,11 +22,44 @@ class TIR(val date: Long, val lowThreshold: Double, val highThreshold: Double) { fun inRange() = run { inRange++; count++ } fun above() = run { above++; count++ } - private fun belowPct() = if (count > 0) (below.toDouble() / count * 100.0).roundToInt() else 0 + private fun belowPct() = if (count > 0) below.toDouble() / count * 100.0 else 0.0 private fun inRangePct() = if (count > 0) 100 - belowPct() - abovePct() else 0 - private fun abovePct() = if (count > 0) (above.toDouble() / count * 100.0).roundToInt() else 0 + private fun abovePct() = if (count > 0) above.toDouble() / count * 100.0 else 0.0 - fun toText(rh: ResourceHelper, dateUtil: DateUtil): String = rh.gs(R.string.tirformat, dateUtil.dateStringShort(date), belowPct(), inRangePct(), abovePct()) + companion object { - fun toText(rh: ResourceHelper, days: Int): String = rh.gs(R.string.tirformat, "%02d".format(days) + " " + rh.gs(R.string.days), belowPct(), inRangePct(), abovePct()) + fun toTableRowHeader(context: Context, rh: ResourceHelper): TableRow = + TableRow(context).also { header -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT) + header.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + header.gravity = Gravity.CENTER_HORIZONTAL + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 0; weight = 1f }; text = rh.gs(R.string.date) }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 1; weight = 1f }; text = rh.gs(R.string.below) }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 2; weight = 1f }; text = rh.gs(R.string.in_range) }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 3; weight = 1f }; text = rh.gs(R.string.above) }) + } + } + + fun toTableRow(context: Context, rh: ResourceHelper, dateUtil: DateUtil): TableRow = + TableRow(context).also { row -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f } + row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + row.gravity = Gravity.CENTER_HORIZONTAL + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 0 }; text = dateUtil.dateStringShort(date) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 1 }; text = rh.gs(R.string.formatPercent, belowPct()) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 2 }; text = rh.gs(R.string.formatPercent, inRangePct()) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 3 }; text = rh.gs(R.string.formatPercent, abovePct()) }) + } + + @SuppressLint("SetTextI18n") + fun toTableRow(context: Context, rh: ResourceHelper, days: Int): TableRow = + TableRow(context).also { row -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f } + row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + row.gravity = Gravity.CENTER_HORIZONTAL + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 0 }; text = "%02d".format(days) + " " + rh.gs(R.string.days) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 1 }; text = rh.gs(R.string.formatPercent, belowPct()) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 2 }; text = rh.gs(R.string.formatPercent, inRangePct()) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 3 }; text = rh.gs(R.string.formatPercent, abovePct()) }) + } } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt index 349dd597c7..6334d5bb91 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt @@ -1,18 +1,25 @@ package info.nightscout.androidaps.utils.stats -import android.text.Spanned +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Typeface import android.util.LongSparseArray +import android.view.Gravity +import android.view.ViewGroup +import android.widget.TableLayout +import android.widget.TableRow +import android.widget.TextView import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.TotalDailyDose import info.nightscout.androidaps.extensions.convertedToAbsolute -import info.nightscout.androidaps.extensions.toText +import info.nightscout.androidaps.extensions.toTableRow +import info.nightscout.androidaps.extensions.toTableRowHeader import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -186,24 +193,31 @@ class TddCalculator @Inject constructor( return totalTdd } - fun stats(): Spanned { + @SuppressLint("SetTextI18n") + fun stats(context: Context): TableLayout { val tdds = calculate(7) val averageTdd = averageTDD(tdds) - return HtmlHelper.fromHtml( - if (averageTdd != null) "" + rh.gs(R.string.tdd) + ":
" + - toText(tdds, true) + - "" + rh.gs(R.string.average) + ":
" + - averageTdd.toText(rh, tdds.size(), true) - else "" - ) - } - - @Suppress("SameParameterValue") - private fun toText(tdds: LongSparseArray, includeCarbs: Boolean): String { - var t = "" - for (i in 0 until tdds.size()) { - t += "${tdds.valueAt(i).toText(rh, dateUtil, includeCarbs)}
" + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT) + return TableLayout(context).also { layout -> + layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) + layout.addView(TextView(context).apply { + text = rh.gs(R.string.tdd) + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + setTextAppearance(android.R.style.TextAppearance_Material_Medium) + }) + layout.addView(TotalDailyDose.toTableRowHeader(context, rh, includeCarbs = true)) + for (i in 0 until tdds.size()) layout.addView(tdds.valueAt(i).toTableRow(context, rh, dateUtil, includeCarbs = true)) + averageTdd?.let { averageTdd -> + layout.addView(TextView(context).apply { + layoutParams = lp + text = rh.gs(R.string.average) + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + setTextAppearance(android.R.style.TextAppearance_Material_Medium) + }) + layout.addView(averageTdd.toTableRow(context, rh, tdds.size(), includeCarbs = true)) + } } - return t } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt index 58ec13ab54..22cd19e030 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt @@ -1,14 +1,19 @@ package info.nightscout.androidaps.utils.stats -import android.text.Spanned +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Typeface import android.util.LongSparseArray +import android.view.Gravity +import android.view.ViewGroup +import android.widget.TableLayout +import android.widget.TextView import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -63,38 +68,49 @@ class TirCalculator @Inject constructor( return totalTir } - fun stats(): Spanned { - val lowTirMgdl = Constants.STATS_RANGE_LOW_MMOL * Constants.MMOLL_TO_MGDL - val highTirMgdl = Constants.STATS_RANGE_HIGH_MMOL * Constants.MMOLL_TO_MGDL - val lowTitMgdl = Constants.STATS_TARGET_LOW_MMOL * Constants.MMOLL_TO_MGDL - val highTitMgdl = Constants.STATS_TARGET_HIGH_MMOL * Constants.MMOLL_TO_MGDL + @SuppressLint("SetTextI18n") + fun stats(context: Context): TableLayout = + TableLayout(context).also { layout -> + val lowTirMgdl = Constants.STATS_RANGE_LOW_MMOL * Constants.MMOLL_TO_MGDL + val highTirMgdl = Constants.STATS_RANGE_HIGH_MMOL * Constants.MMOLL_TO_MGDL + val lowTitMgdl = Constants.STATS_TARGET_LOW_MMOL * Constants.MMOLL_TO_MGDL + val highTitMgdl = Constants.STATS_TARGET_HIGH_MMOL * Constants.MMOLL_TO_MGDL - val tir7 = calculate(7, lowTirMgdl, highTirMgdl) - val averageTir7 = averageTIR(tir7) - val tir30 = calculate(30, lowTirMgdl, highTirMgdl) - val averageTir30 = averageTIR(tir30) - val tit7 = calculate(7, lowTitMgdl, highTitMgdl) - val averageTit7 = averageTIR(tit7) - val tit30 = calculate(30, lowTitMgdl, highTitMgdl) - val averageTit30 = averageTIR(tit30) - return HtmlHelper.fromHtml( - "
" + rh.gs(R.string.tir) + " (" + Profile.toCurrentUnitsString(profileFunction, lowTirMgdl) + "-" + Profile.toCurrentUnitsString(profileFunction, highTirMgdl) + "):
" + - toText(rh, tir7) + - "
" + rh.gs(R.string.average) + " (" + Profile.toCurrentUnitsString(profileFunction, lowTirMgdl) + "-" + Profile.toCurrentUnitsString(profileFunction, highTirMgdl) + "):
" + - averageTir7.toText(rh, tir7.size()) + "
" + - averageTir30.toText(rh, tir30.size()) + - "
" + rh.gs(R.string.average) + " (" + Profile.toCurrentUnitsString(profileFunction, lowTitMgdl) + "-" + Profile.toCurrentUnitsString(profileFunction, highTitMgdl) + "):
" + - averageTit7.toText(rh, tit7.size()) + "
" + - averageTit30.toText(rh, tit30.size()) - ) - } - - fun toText(rh: ResourceHelper, tirs: LongSparseArray): String { - var t = "" - for (i in 0 until tirs.size()) { - t += "${tirs.valueAt(i).toText(rh, dateUtil)}
" + val tir7 = calculate(7, lowTirMgdl, highTirMgdl) + val averageTir7 = averageTIR(tir7) + val tir30 = calculate(30, lowTirMgdl, highTirMgdl) + val averageTir30 = averageTIR(tir30) + val tit7 = calculate(7, lowTitMgdl, highTitMgdl) + val averageTit7 = averageTIR(tit7) + val tit30 = calculate(30, lowTitMgdl, highTitMgdl) + val averageTit30 = averageTIR(tit30) + layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) + layout.addView( + TextView(context).apply { + text = rh.gs(R.string.tir) + " (" + Profile.toCurrentUnitsString(profileFunction, lowTirMgdl) + "-" + Profile.toCurrentUnitsString(profileFunction, highTirMgdl) + ")" + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + setTextAppearance(android.R.style.TextAppearance_Material_Medium) + }) + layout.addView(TIR.toTableRowHeader(context, rh)) + for (i in 0 until tir7.size()) layout.addView(tir7.valueAt(i).toTableRow(context, rh, dateUtil)) + layout.addView( + TextView(context).apply { + text = rh.gs(R.string.average) + " (" + Profile.toCurrentUnitsString(profileFunction, lowTirMgdl) + "-" + Profile.toCurrentUnitsString(profileFunction, highTirMgdl) + ")" + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + setTextAppearance(android.R.style.TextAppearance_Material_Medium) + }) + layout.addView(averageTir7.toTableRow(context, rh, tir7.size())) + layout.addView(averageTir30.toTableRow(context, rh, tir30.size())) + layout.addView( + TextView(context).apply { + text = rh.gs(R.string.average) + " (" + Profile.toCurrentUnitsString(profileFunction, lowTitMgdl) + "-" + Profile.toCurrentUnitsString(profileFunction, highTitMgdl) + ")" + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + setTextAppearance(android.R.style.TextAppearance_Material_Medium) + }) + layout.addView(averageTit7.toTableRow(context, rh, tit7.size())) + layout.addView(averageTit30.toTableRow(context, rh, tit30.size())) } - return t - } - } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_profilehelper.xml b/app/src/main/res/layout/activity_profilehelper.xml index cf3d6f2ffb..2e3652bc51 100644 --- a/app/src/main/res/layout/activity_profilehelper.xml +++ b/app/src/main/res/layout/activity_profilehelper.xml @@ -16,7 +16,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/defaultbackground" - android:orientation="horizontal"> + android:orientation="horizontal" + android:paddingBottom="10dp"> + android:text="1" + tools:ignore="HardcodedText" /> + android:text="2" + tools:ignore="HardcodedText" /> @@ -168,15 +171,15 @@ - + android:orientation="vertical" /> - + android:orientation="vertical" /> - + android:layout_marginTop="20dp" + android:orientation="vertical" /> - + android:layout_marginTop="20dp" + android:orientation="vertical" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 834e146a4f..4f92df3fc6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -163,7 +163,6 @@ Calculator Constraint applied! Bolus: - Basal Basal: Change your input! BG Source @@ -967,7 +966,6 @@ Invalid age entry Invalid weight entry Invalid % entry - %1$s: Low: %2$02d%% In: %3$02d%% High: %4$02d%%]]> Average TIR Activity monitor @@ -1235,4 +1233,7 @@ %1$d selected Sort Dialog canceled + Below + In range + Above diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/TotalDailyDoseExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/TotalDailyDoseExtension.kt index 31f228125f..31d34ea29d 100644 --- a/core/src/main/java/info/nightscout/androidaps/extensions/TotalDailyDoseExtension.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/TotalDailyDoseExtension.kt @@ -1,5 +1,10 @@ package info.nightscout.androidaps.extensions +import android.annotation.SuppressLint +import android.content.Context +import android.view.Gravity +import android.widget.TableRow +import android.widget.TextView import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.TotalDailyDose import info.nightscout.androidaps.utils.DateUtil @@ -11,12 +16,49 @@ val TotalDailyDose.total val TotalDailyDose.basalPct: Double get() = if (total > 0) basalAmount / total * 100 else 0.0 -fun TotalDailyDose.toText(rh: ResourceHelper, dateUtil: DateUtil, includeCarbs: Boolean): String = - if (total.isNaN() || bolusAmount.isNaN() || basalAmount.isNaN() || carbs.isNaN()) "" - else if (includeCarbs) rh.gs(R.string.tddwithcarbsformat, dateUtil.dateStringShort(timestamp), total, bolusAmount, basalAmount, basalPct, carbs) - else rh.gs(R.string.tddformat, dateUtil.dateStringShort(timestamp), total, bolusAmount, basalAmount, basalPct) +fun TotalDailyDose.Companion.toTableRowHeader(context: Context, rh: ResourceHelper, includeCarbs: Boolean): TableRow = + TableRow(context).also { header -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT) + header.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + header.gravity = Gravity.CENTER_HORIZONTAL + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 0; weight = 1f }; text = rh.gs(R.string.date) }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 1; weight = 1f }; text = "∑" }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 2; weight = 1f }; text = rh.gs(R.string.bolus) }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 3; weight = 1f }; text = rh.gs(R.string.basal) }) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 4; weight = 1f }; text = rh.gs(R.string.basalpct) }) + if (includeCarbs) + header.addView(TextView(context).apply { layoutParams = lp.apply { column = 5; weight = 1f }; text = rh.gs(R.string.carbs) }) + } -fun TotalDailyDose.toText(rh: ResourceHelper, days: Int, includeCarbs: Boolean): String = - if (total.isNaN() || bolusAmount.isNaN() || basalAmount.isNaN() || carbs.isNaN()) "" - else if (includeCarbs) rh.gs(R.string.tddwithcarbsformat, days.toString() + rh.gs(R.string.days), total, bolusAmount, basalAmount, basalAmount / total * 100, carbs) - else rh.gs(R.string.tddformat, days.toString() + rh.gs(R.string.days), total, bolusAmount, basalAmount, basalAmount / total * 100) +fun TotalDailyDose.toTableRow(context: Context, rh: ResourceHelper, dateUtil: DateUtil, includeCarbs: Boolean): TableRow = + TableRow(context).also { row -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f } + if ((total.isNaN() || bolusAmount.isNaN() || basalAmount.isNaN() || carbs.isNaN()).not()) { + row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + row.gravity = Gravity.CENTER_HORIZONTAL + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 0 }; text = dateUtil.dateStringShort(timestamp) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 1 }; text = rh.gs(R.string.formatinsulinunits1, total) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 2 }; text = rh.gs(R.string.formatinsulinunits1, bolusAmount) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 3 }; text = rh.gs(R.string.formatinsulinunits1, basalAmount) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 4 }; text = rh.gs(R.string.formatPercent, basalPct) }) + if (includeCarbs) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 5 }; text = rh.gs(R.string.formatinsulinunits1, carbs) }) + } + } + +@SuppressLint("SetTextI18n") +fun TotalDailyDose.toTableRow(context: Context, rh: ResourceHelper, days: Int, includeCarbs: Boolean): TableRow = + TableRow(context).also { row -> + val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT).apply { weight = 1f } + if ((total.isNaN() || bolusAmount.isNaN() || basalAmount.isNaN() || carbs.isNaN()).not()) { + row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) + row.gravity = Gravity.CENTER_HORIZONTAL + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 0 }; text = "%02d".format(days) + " " + rh.gs(R.string.days) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 1 }; text = rh.gs(R.string.formatinsulinunits1, total) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 2 }; text = rh.gs(R.string.formatinsulinunits1, bolusAmount) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 3 }; text = rh.gs(R.string.formatinsulinunits1, basalAmount) }) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 4 }; text = rh.gs(R.string.formatPercent, basalPct) }) + if (includeCarbs) + row.addView(TextView(context).apply { layoutParams = lp.apply { column = 5 }; text = rh.gs(R.string.formatinsulinunits1, carbs) }) + } + } diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index cee8777b62..1e2c53c19e 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -263,11 +263,6 @@ %1$d min - - %1$s: ∑: %2$.2f U Bol: %3$.2f U Bas: %4$.2f U(%5$.0f%%)]]> - %1$s: ∑: %2$.2f U Bol: %3$.2f U Bas: %4$.2f U(%5$.0f%%) Carbs: %6$.0f g]]> - %1$s: %2$s in %3$d days
]]>
- Careportal BG Check @@ -558,6 +553,9 @@ Insight Refresh Button decrement %1$s by %2$s increment %1$s by %2$s + %1$.0f%% + Basal + Basal % %1$d day diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt index a45330c844..2426147b54 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt @@ -40,4 +40,6 @@ data class TotalDailyDose( var bolusAmount: Double = 0.0, var totalAmount: Double = 0.0, // if zero it's calculated as basalAmount + bolusAmount var carbs: Double = 0.0 -) : TraceableDBEntry, DBEntryWithTime \ No newline at end of file +) : TraceableDBEntry, DBEntryWithTime { + companion object +} \ No newline at end of file