improve statistics

This commit is contained in:
2025-11-26 23:04:22 +01:00
parent 8adacd3bfe
commit 0a424e8807
5 changed files with 429 additions and 156 deletions

View File

@@ -17,24 +17,39 @@ import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.formatter.ValueFormatter import com.github.mikephil.charting.formatter.ValueFormatter
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet import com.github.mikephil.charting.interfaces.datasets.IBarDataSet
import it.danieleverducci.lunatracker.entities.LunaEvent import it.danieleverducci.lunatracker.entities.LunaEvent
import utils.DateUtils.Companion.formatTimeDuration
import utils.NumericUtils import utils.NumericUtils
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import androidx.core.graphics.toColorInt
class StatisticsActivity : AppCompatActivity() { class StatisticsActivity : AppCompatActivity() {
lateinit var barChart: BarChart lateinit var barChart: BarChart
lateinit var noDataTextView: TextView lateinit var noDataTextView: TextView
lateinit var eventTypeSelection: Spinner lateinit var graphTypeSpinner: Spinner
lateinit var dataTypeSelection: Spinner //lateinit var dataTypeSelection: Spinner
lateinit var timeRangeSelection: Spinner lateinit var timeRangeSpinner: Spinner
enum class GraphType {
BOTTLE_EVENTS,
BOTTLE_SUM,
BOTTLE_SUM_AVERAGE,
SLEEP_SUM,
SLEEP_SUM_AVERAGE,
SLEEP_EVENTS,
SLEEP_PATTERN
}
enum class RangeType {
DAY,
WEEK,
MONTH
}
// default selection // default selection
var eventTypeSelectionValue = "BOTTLE" var graphTypeSelection = GraphType.SLEEP_SUM
var dataTypeSelectionValue = "AMOUNT" var timeRangeSelection = RangeType.DAY
var timeRangeSelectionValue = "DAY"
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -65,25 +80,38 @@ class StatisticsActivity : AppCompatActivity() {
barChart.xAxis.setDrawLabels(true) barChart.xAxis.setDrawLabels(true)
barChart.xAxis.setDrawAxisLine(false) barChart.xAxis.setDrawAxisLine(false)
eventTypeSelection = findViewById(R.id.type_selection) graphTypeSpinner = findViewById(R.id.type_selection)
dataTypeSelection = findViewById(R.id.data_selection) //dataTypeSelection = findViewById(R.id.data_selection)
timeRangeSelection = findViewById(R.id.time_selection) timeRangeSpinner = findViewById(R.id.time_selection)
setupSpinner(eventTypeSelectionValue, setupSpinner("SLEEP_SUM",
R.id.type_selection, R.id.type_selection,
R.array.StatisticsTypeLabels, R.array.StatisticsTypeLabels,
R.array.StatisticsTypeValues, R.array.StatisticsTypeValues,
object : SpinnerItemSelected { object : SpinnerItemSelected {
override fun call(newValue: String?) { override fun call(newValue: String?) {
if (newValue != null) { newValue ?: return
eventTypeSelectionValue = newValue graphTypeSelection = when (newValue) {
//Log.d("event", "new value: $newValue") "BOTTLE_EVENTS" -> GraphType.BOTTLE_EVENTS
updateGraph() "BOTTLE_SUM" -> GraphType.BOTTLE_SUM
"BOTTLE_SUM_AVERAGE" -> GraphType.BOTTLE_SUM_AVERAGE
"SLEEP_SUM_AVERAGE" -> GraphType.SLEEP_SUM_AVERAGE
"SLEEP_SUM" -> GraphType.SLEEP_SUM
"SLEEP_SUM_AVERAGE" -> GraphType.SLEEP_SUM_AVERAGE
"SLEEP_EVENTS" -> GraphType.SLEEP_EVENTS
"SLEEP_PATTERN" -> GraphType.SLEEP_PATTERN
else -> {
Log.e(TAG, "Invalid graph type selection: $newValue")
return
}
} }
//Log.d("event", "new value: $newValue")
updateGraph()
} }
} }
) )
/*
setupSpinner(dataTypeSelectionValue, setupSpinner(dataTypeSelectionValue,
R.id.data_selection, R.id.data_selection,
R.array.StatisticsDataLabels, R.array.StatisticsDataLabels,
@@ -98,18 +126,25 @@ class StatisticsActivity : AppCompatActivity() {
} }
} }
) )
*/
setupSpinner(timeRangeSelectionValue, setupSpinner("DAY",
R.id.time_selection, R.id.time_selection,
R.array.StatisticsTimeLabels, R.array.StatisticsTimeLabels,
R.array.StatisticsTimeValues, R.array.StatisticsTimeValues,
object : SpinnerItemSelected { object : SpinnerItemSelected {
override fun call(newValue: String?) { override fun call(newValue: String?) {
if (newValue != null) { newValue ?: return
timeRangeSelectionValue = newValue timeRangeSelection = when (newValue) {
//Log.d("event", "new value: $newValue") "DAY" -> RangeType.DAY
updateGraph() "WEEK" -> RangeType.WEEK
"MONTH" -> RangeType.MONTH
else -> {
Log.e(TAG, "Invalid time range selection: $newValue")
return
}
} }
//Log.d("event", "new value: $newValue")
updateGraph()
} }
} }
) )
@@ -117,123 +152,206 @@ class StatisticsActivity : AppCompatActivity() {
updateGraph() updateGraph()
} }
fun updateGraph() { fun showSleepBarGraph(events: List<LunaEvent>, unixToSpan: (Long) -> Int, spanToUnix: (Int) -> Long) {
val eventType = when (eventTypeSelectionValue) { fun getEndTime(event: LunaEvent): Long {
"BOTTLE" -> LunaEvent.TYPE_BABY_BOTTLE if (event.quantity == 0) {
"SLEEP" -> LunaEvent.TYPE_SLEEP // sleep is still ongoing
else -> { val dateTime = Calendar.getInstance()
Log.e(TAG, "unhandled eventTypeSelectionValue: $eventTypeSelectionValue") return (dateTime.time.time / 1000) - event.time
return } else {
return event.quantity.toLong()
} }
} }
val allEvents = MainActivity.allEvents.filter { it.type == eventType }.sortedBy { it.time }
data class SleepRange(val start: Long, val end: Long)
val ranges = arrayListOf<SleepRange>()
// Transform events into time ranges.
// Merge overlapping times and extend
// ongoing sleep events until now.
val dateTime = Calendar.getInstance()
for (event in events) {
val endTime = if (event.quantity == 0) {
dateTime.time.time / 1000 // now
} else {
event.time + event.quantity
}
/*
// TODO: handle overlap
if (ranges.isNotEmpty()) {
val lastItem = ranges.lastItem()
if (lastItem.start)
if (lastItem.end <= event.time) {
// distinct
}
}
}
*/
ranges.add(SleepRange(event.time, endTime))
}
// unix time span of all events
val startUnix = events.minOf { it.time }
val endUnix = events.maxOf { getEndTime(it) }
// convert to days, weeks or months
val startSpan = unixToSpan(startUnix)
val endSpan = unixToSpan(endUnix)
val values = ArrayList<BarEntry>() val values = ArrayList<BarEntry>()
val labels = ArrayList<String>()
val unixToSpan = when (timeRangeSelectionValue) { fun countEvent(index: Int) {
"DAY" -> { unix: Long -> unixToDays(unix) } // create initial values
"WEEK" -> { unix: Long -> unixToWeeks(unix) } while (index >= values.size) {
"MONTH" -> { unix: Long -> unixToMonths(unix) }
else -> {
Log.e(TAG, "Invalid timeRangeSelectionValue: $timeRangeSelectionValue")
return
}
}
val spanToUnix = when (timeRangeSelectionValue) {
"DAY" -> { span: Int -> daysToUnix(span) }
"WEEK" -> { span: Int -> weeksToUnix(span) }
"MONTH" -> { span: Int -> monthsToUnix(span) }
else -> {
Log.e(TAG, "Invalid timeRangeSelectionValue: $timeRangeSelectionValue")
return
}
}
fun spanToLabel(span: Int): String {
val dateTime = Calendar.getInstance()
dateTime.time = Date(1000 * spanToUnix(span))
val year = dateTime.get(Calendar.YEAR)
val month = dateTime.get(Calendar.MONTH) + 1 // month starts at 0
val week = dateTime.get(Calendar.WEEK_OF_YEAR)
val day = dateTime.get(Calendar.DAY_OF_MONTH)
return when (timeRangeSelectionValue) {
"DAY" -> "$day/$month/$year"
"WEEK" -> "$week/$year"
"MONTH" -> "$month/$year"
else -> {
Log.e(TAG, "Invalid timeRangeSelectionValue: $timeRangeSelectionValue")
"?"
}
}
}
if (allEvents.isNotEmpty()) {
barChart.visibility = View.VISIBLE
noDataTextView.visibility = View.GONE
// unix time span of all events
val startUnix = allEvents.minOf { it.getStartTime() }
val endUnix = allEvents.maxOf { it.getEndTime() }
// convert to days, weeks or months
val startSpan = unixToSpan(startUnix)
val endSpan = unixToSpan(endUnix)
//Log.d(TAG, "startUnix: $startUnix (${Date(1000 * startUnix)}), startSpan: $startSpan (${Date(1000 * spanToUnix(startSpan))}), endUnix: $endUnix (${Date(1000 * endUnix)}), endSpan: $endSpan (${Date(1000 * spanToUnix(endSpan))})")
for (span in startSpan..endSpan) {
values.add(BarEntry(values.size.toFloat(), 0F)) values.add(BarEntry(values.size.toFloat(), 0F))
labels.add(spanToLabel(span))
} }
for (event in allEvents) { // update value
if (dataTypeSelectionValue == "AMOUNT") { values[index].y += 1F
if (eventTypeSelectionValue == "SLEEP") {
// a sleep event can span to another day
// distribute sleep time over the days
val startUnix = event.getStartTime()
val endUnix = event.getEndTime()
val begIndex = unixToSpan(startUnix)
val endIndex = unixToSpan(endUnix)
var mid = startUnix
//Log.d(TAG, "startUnix: ${Date(startUnix * 1000)}, endUnix: ${Date(endUnix * 1000)}, begIndex: $begIndex, endIndex: $endIndex (index diff: ${endIndex - begIndex})")
for (i in begIndex..endIndex) {
val spanBegin = spanToUnix(i)
val spanEnd = spanToUnix(i + 1)
//Log.d(TAG, "mid: ${Date(mid * 1000)}, spanBegin: ${Date(spanBegin * 1000)}, spanEnd: ${Date(spanEnd * 1000)}, endUnix: ${Date(endUnix * 1000)}")
val beg = max(mid, spanBegin)
val end = min(endUnix, spanEnd)
val index = i - startSpan
val duration = end - beg
//Log.d(TAG, "[$index] beg: ${Date(beg * 1000)}, end: ${Date(end * 1000)}, ${formatTimeDuration(this, duration)}")
values[index].y += duration
mid = end
}
} else {
val index = unixToSpan(event.time) - startSpan
//Log.d(TAG, "[${index}] ${event.quantity}")
values[index].y += event.quantity
}
} else {
val index = unixToSpan(event.time) - startSpan
values[index].y += 1
}
}
} else {
barChart.visibility = View.GONE
noDataTextView.visibility = View.VISIBLE
} }
barChart.xAxis.setLabelCount(min(values.size, 24)) fun accumulateValue(index: Int, value: Long) {
// create initial values
while (index >= values.size) {
values.add(BarEntry(values.size.toFloat(), 0F))
}
// update value
values[index].y += value.toFloat()
}
fun stackValue(index: Int, value: Long) {
// create initial values
while (index >= values.size) {
values.add(BarEntry(values.size.toFloat(), FloatArray(0)))
}
val x = values[index].x
val yVals = values[index].yVals
// update value
val newYVals = appendToFloatArray(yVals, value.toFloat())
values[index] = BarEntry(x, newYVals)
}
// awake/sleep
fun stackValuePattern(index: Int, spanBegin: Long, spanEnd: Long, begin: Long, end: Long) {
// create initial values
while (index >= values.size) {
values.add(BarEntry(values.size.toFloat(), FloatArray(0)))
}
assert(begin in spanBegin..spanEnd)
assert(end in spanBegin..spanEnd)
assert(begin <= end)
val x = values[index].x
val yVals = values[index].yVals // alternating sleep/awake durations
val y = yVals.fold(0F) { acc, next -> acc + next }
// y value is seconds when last awake
val awakeDuration = max(begin - spanBegin - y.toLong(), 0L)
val sleepDuration = end - begin
if ((awakeDuration + sleepDuration) > (spanEnd - spanBegin)) {
Log.e(TAG, "Invalid sleep duration, exceeds day/week or month bounds => ignore value")
return
}
// update value
val newYVals = appendToFloatArray(yVals, awakeDuration.toFloat(), sleepDuration.toFloat())
values[index] = BarEntry(x, newYVals)
}
/*
fun addStack24hCap(spanDuration: Long) {
// spanDuration is usually a day, week, month in seconds
Log.d(TAG, "spanDuration: $spanDuration, ${24*60*60}")
for (i in values.indices) {
val x = values[i].x
val yVals = values[i].yVals
val y = yVals.fold(0F) { acc, next -> acc + next }
val cap = spanDuration.toFloat() - y
if (cap >= 0F) {
// Add a cap value and an 0 value to keep the number of spans even.
// This is important, since we configure two colors and they will alternate.
val newYVals = appendToFloatArray(yVals, cap, 0F)
values[i] = BarEntry(x, newYVals)
} else {
Log.e(TAG, "Invalid remaining sleep duration, exceeds day/week or month bounds => ignore")
}
}
}
*/
for (range in ranges) {
// a sleep event can span to another day
// distribute sleep time over the days
val startUnix = range.start //event.time
val endUnix = range.end //getEndTime(event)
val begIndex = unixToSpan(startUnix)
val endIndex = unixToSpan(endUnix)
var mid = startUnix
//Log.d(TAG, "startUnix: ${Date(startUnix * 1000)}, endUnix: ${Date(endUnix * 1000)}, begIndex: $begIndex, endIndex: $endIndex (index diff: ${endIndex - begIndex})")
for (i in begIndex..endIndex) {
val spanBegin = spanToUnix(i)
val spanEnd = spanToUnix(i + 1)
//Log.d(TAG, "mid: ${Date(mid * 1000)}, spanBegin: ${Date(spanBegin * 1000)}, spanEnd: ${Date(spanEnd * 1000)}, endUnix: ${Date(endUnix * 1000)}")
val sleepBegin = max(mid, spanBegin)
val sleepEnd = min(endUnix, spanEnd)
val index = i - startSpan
val duration = sleepEnd - sleepBegin
//Log.d(TAG, "[$index] sleepBegin: ${Date(sleepBegin * 1000)}, sleepEnd: ${Date(sleepEnd * 1000)}, ${formatTimeDuration(this, duration)}")
if (graphTypeSelection == GraphType.SLEEP_PATTERN) {
stackValuePattern(index, spanBegin, spanEnd, sleepBegin, sleepEnd)
} else if (graphTypeSelection == GraphType.SLEEP_SUM) {
stackValue(index, duration)
} else if (graphTypeSelection == GraphType.SLEEP_SUM_AVERAGE) {
accumulateValue(index, duration)
} else if (graphTypeSelection == GraphType.SLEEP_EVENTS) {
countEvent(index)
} else {
Log.e(TAG, "Unexpected graph type.")
return
}
mid = sleepEnd
}
// TODO: move addStack24h here, since the spans can have different length (edge case and does not really matter)
}
//addStack24hCap(spanToUnix(1) - spanToUnix(0))
// for debugging
for (value in values) {
val y = value.yVals.fold(0F) { acc, next -> acc + next }
val yVals = value.yVals.joinToString { it.toString() }
Log.d(TAG, "value: ${value.x} $y ($yVals)")
}
// list of dates
val labels = ArrayList<String>()
for (index in values.indices) {
labels.add(spanToLabel(spanToUnix(startSpan + index)))
}
val set1 = BarDataSet(values, "") val set1 = BarDataSet(values, "")
set1.setDrawValues(true) if (graphTypeSelection == GraphType.SLEEP_PATTERN) {
// awake phase color is transparent
set1.colors = arrayListOf("#00000000".toColorInt(), ColorTemplate.rgb("#72d7f5"))
set1.setDrawValues(false) // too many values => let's disable it
} else {
set1.setDrawValues(false)
}
set1.setDrawIcons(false) set1.setDrawIcons(false)
barChart.legend.isEnabled = false
barChart.xAxis.setLabelCount(min(values.size, 24))
val dataSets = ArrayList<IBarDataSet?>() val dataSets = ArrayList<IBarDataSet?>()
dataSets.add(set1) dataSets.add(set1)
@@ -242,17 +360,99 @@ class StatisticsActivity : AppCompatActivity() {
data.setValueFormatter(object : ValueFormatter() { data.setValueFormatter(object : ValueFormatter() {
override fun getFormattedValue(value: Float): String { override fun getFormattedValue(value: Float): String {
//Log.d(TAG, "getFormattedValue ${dataTypeSelectionValue} ${eventTypeSelectionValue}") //Log.d(TAG, "getFormattedValue ${dataTypeSelectionValue} ${eventTypeSelectionValue}")
return when (dataTypeSelectionValue) { return NumericUtils(applicationContext).formatEventQuantity(LunaEvent.TYPE_SLEEP, value.toInt())
"EVENT" -> value.toInt().toString() }
"AMOUNT" -> when (eventTypeSelectionValue) { })
"BOTTLE" -> NumericUtils(applicationContext).formatEventQuantity(LunaEvent.TYPE_BABY_BOTTLE, value.toInt())
"SLEEP" -> NumericUtils(applicationContext).formatEventQuantity(LunaEvent.TYPE_SLEEP, value.toInt()) barChart.xAxis.valueFormatter = object: ValueFormatter() {
else -> { override fun getFormattedValue(value: Float): String {
Log.e(TAG, "unhandled eventTypeSelectionValue: $eventTypeSelectionValue") return labels.getOrElse(value.toInt(), {"?"})
value.toInt().toString() }
} }
} else -> {
Log.e(TAG, "unhandled dataTypeSelectionValue: $dataTypeSelectionValue") //data.setValueTextSize(12f)
barChart.setData(data)
barChart.invalidate()
}
fun showBottleBarGraph(events: List<LunaEvent>, unixToSpan: (Long) -> Int, spanToUnix: (Int) -> Long) {
// unix time span of all events
val startUnix = events.minOf { it.time }
val endUnix = events.maxOf { it.time }
// convert to days, weeks or months
val startSpan = unixToSpan(startUnix)
val endSpan = unixToSpan(endUnix)
val values = ArrayList<BarEntry>()
fun countValue(index: Int) {
// create initial values
while (index >= values.size) {
values.add(BarEntry(values.size.toFloat(), 0F))
}
// update value
values[index].y += 1F
}
fun accumulateValue(index: Int, duration: Long) {
// create initial values
while (index >= values.size) {
values.add(BarEntry(values.size.toFloat(), 0F))
}
// update value
values[index].y += duration.toFloat()
}
for (event in events) {
if (graphTypeSelection == GraphType.BOTTLE_EVENTS) {
val index = unixToSpan(event.time) - startSpan
countValue(index)
} else if (graphTypeSelection == GraphType.BOTTLE_SUM) {
val index = unixToSpan(event.time) - startSpan
//Log.d(TAG, "[${index}] ${event.quantity}")
accumulateValue(index, event.quantity.toLong())
} else {
Log.e(TAG, "unhandled graphTypeSelection")
return
}
}
// list of dates
val labels = ArrayList<String>()
for (index in values.indices) {
labels.add(spanToLabel(spanToUnix(startSpan + index)))
}
val set1 = BarDataSet(values, "")
set1.setDrawValues(true)
set1.setDrawIcons(false)
//showGraph(set1, valueLabels)
// for debugging
//val sum1 = allEvents.fold(0) { acc, event -> acc + event.quantity }
//val sum2 = values.fold(0F) { acc, item -> acc + item.y }
//Log.d(TAG, "sum1: $sum1, sum2: $sum2")
barChart.xAxis.setLabelCount(min(values.size, 24))
val dataSets = ArrayList<IBarDataSet?>()
dataSets.add(set1)
val data = BarData(dataSets)
data.setValueFormatter(object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
//Log.d(TAG, "getFormattedValue ${dataTypeSelectionValue} ${eventTypeSelectionValue}")
return when (graphTypeSelection) {
GraphType.BOTTLE_EVENTS -> value.toInt().toString()
GraphType.BOTTLE_SUM -> NumericUtils(applicationContext).formatEventQuantity(LunaEvent.TYPE_BABY_BOTTLE, value.toInt())
else -> {
Log.e(TAG, "unhandled graphTypeSelection")
value.toInt().toString() value.toInt().toString()
} }
} }
@@ -270,6 +470,64 @@ class StatisticsActivity : AppCompatActivity() {
barChart.invalidate() barChart.invalidate()
} }
fun spanToLabel(unixSeconds: Long): String {
val dateTime = Calendar.getInstance()
dateTime.time = Date(1000L * unixSeconds)
val year = dateTime.get(Calendar.YEAR)
val month = dateTime.get(Calendar.MONTH) + 1 // month starts at 0
val week = dateTime.get(Calendar.WEEK_OF_YEAR)
val day = dateTime.get(Calendar.DAY_OF_MONTH)
return when (timeRangeSelection) {
RangeType.DAY -> "$day/$month/$year"
RangeType.WEEK -> "$week/$year"
RangeType.MONTH -> "$month/$year"
}
}
fun updateGraph() {
val unixToSpan = when (timeRangeSelection) {
RangeType.DAY -> { unix: Long -> unixToDays(unix) }
RangeType.WEEK -> { unix: Long -> unixToWeeks(unix) }
RangeType.MONTH -> { unix: Long -> unixToMonths(unix) }
}
val spanToUnix = when (timeRangeSelection) {
RangeType.DAY -> { span: Int -> daysToUnix(span) }
RangeType.WEEK -> { span: Int -> weeksToUnix(span) }
RangeType.MONTH -> { span: Int -> monthsToUnix(span) }
}
val eventType = when (graphTypeSelection) {
GraphType.BOTTLE_EVENTS,
GraphType.BOTTLE_SUM,
GraphType.BOTTLE_SUM_AVERAGE -> LunaEvent.TYPE_BABY_BOTTLE
GraphType.SLEEP_SUM,
GraphType.SLEEP_SUM_AVERAGE,
GraphType.SLEEP_EVENTS,
GraphType.SLEEP_PATTERN -> LunaEvent.TYPE_SLEEP
}
val events = MainActivity.allEvents.filter { it.type == eventType }.sortedBy { it.time }
if (events.isEmpty()) {
barChart.visibility = View.GONE
noDataTextView.visibility = View.VISIBLE
} else {
barChart.visibility = View.VISIBLE
noDataTextView.visibility = View.GONE
when (graphTypeSelection) {
GraphType.BOTTLE_EVENTS,
GraphType.BOTTLE_SUM,
GraphType.BOTTLE_SUM_AVERAGE -> showBottleBarGraph(events, unixToSpan, spanToUnix)
GraphType.SLEEP_SUM,
GraphType.SLEEP_SUM_AVERAGE,
GraphType.SLEEP_EVENTS,
GraphType.SLEEP_PATTERN -> showSleepBarGraph(events, unixToSpan, spanToUnix)
}
}
}
private interface SpinnerItemSelected { private interface SpinnerItemSelected {
fun call(newValue: String?) fun call(newValue: String?)
} }
@@ -370,5 +628,19 @@ class StatisticsActivity : AppCompatActivity() {
dateTime.set(Calendar.SECOND, 0) dateTime.set(Calendar.SECOND, 0)
return dateTime.time.time / 1000 return dateTime.time.time / 1000
} }
fun appendToFloatArray(array: FloatArray, vararg values: Float): FloatArray {
// create new array
val newArray = FloatArray(array.size + values.size)
// copy old values
for (i in array.indices) {
newArray[i] = array[i]
}
// add new values
for (i in values.indices) {
newArray[array.size + i] = values[i]
}
return newArray
}
} }
} }

View File

@@ -59,7 +59,12 @@ class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.Lu
LunaEvent.TYPE_CUSTOM -> item.notes LunaEvent.TYPE_CUSTOM -> item.notes
else -> item.getTypeDescription(context) else -> item.getTypeDescription(context)
} }
holder.time.text = DateUtils.formatTimeAgo(context, item.getEndTime()) val endTime = if (item.type == LunaEvent.TYPE_SLEEP) {
item.quantity + item.time
} else {
item.time
}
holder.time.text = DateUtils.formatTimeAgo(context, endTime)
var quantityText = numericUtils.formatEventQuantity(item) var quantityText = numericUtils.formatEventQuantity(item)
// if the event is weight, show difference with the last one // if the event is weight, show difference with the last one

View File

@@ -94,18 +94,6 @@ class LunaEvent: Comparable<LunaEvent> {
this.quantity = quantity this.quantity = quantity
} }
fun getStartTime(): Long {
return time
}
fun getEndTime(): Long {
return if (type == TYPE_SLEEP) {
time + quantity
} else {
time
}
}
fun getTypeEmoji(context: Context): String { fun getTypeEmoji(context: Context): String {
return context.getString( return context.getString(
when (type) { when (type) {

View File

@@ -37,14 +37,14 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:layout_weight="1" /> android:layout_weight="1" />
<!--
<Spinner <Spinner
android:id="@+id/data_selection" android:id="@+id/data_selection"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:layout_weight="1"/> android:layout_weight="1"/>
-->
<Spinner <Spinner
android:id="@+id/time_selection" android:id="@+id/time_selection"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -8,15 +8,23 @@
</string-array> </string-array>
<string-array name="StatisticsTypeLabels"> <string-array name="StatisticsTypeLabels">
<item>Bottle</item> <item>BOTTLE_EVENTS</item>
<item>Sleep</item> <item>BOTTLE_SUM</item>
<item>BOTTLE_SUM_AVERAGE</item>
<item>SLEEP_SUM_AVERAGE</item>
<item>SLEEP_EVENTS</item>
<item>SLEEP_PATTERN</item>
</string-array> </string-array>
<string-array name="StatisticsTypeValues"> <string-array name="StatisticsTypeValues">
<item>BOTTLE</item> <item>BOTTLE_EVENTS</item>
<item>SLEEP</item> <item>BOTTLE_SUM</item>
<item>BOTTLE_SUM_AVERAGE</item>
<item>SLEEP_SUM_AVERAGE</item>
<item>SLEEP_EVENTS</item>
<item>SLEEP_PATTERN</item>
</string-array> </string-array>
<!--
<string-array name="StatisticsDataLabels"> <string-array name="StatisticsDataLabels">
<item>Event</item> <item>Event</item>
<item>Amount</item> <item>Amount</item>
@@ -26,7 +34,7 @@
<item>EVENT</item> <item>EVENT</item>
<item>AMOUNT</item> <item>AMOUNT</item>
</string-array> </string-array>
-->
<string-array name="StatisticsTimeLabels"> <string-array name="StatisticsTimeLabels">
<item>Day</item> <item>Day</item>
<item>Week</item> <item>Week</item>