View Skipped Days In The Bar Chart

I noticed that the skipped days appear in the history chart but not in the bar chart so I modified the code adding a piece of code to pass the skipped days data from database to the view and drawing a bar with a slightly transparent color -to let it be different from the main column- accordingly.
pull/1736/head
Mahmoud-Ibrahim-750 2 years ago
parent 499eb467cb
commit e107a1c51b

@ -40,6 +40,7 @@ class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context,
val androidColor = state.theme.color(state.color).toInt() val androidColor = state.theme.color(state.color).toInt()
binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.US)).apply { binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.US)).apply {
series = mutableListOf(state.entries.map { it.value / 1000.0 }) series = mutableListOf(state.entries.map { it.value / 1000.0 })
skippedSeries = mutableListOf(state.skippedEntries.map { it.value / 1.0 })
colors = mutableListOf(theme.color(state.color.paletteIndex)) colors = mutableListOf(theme.color(state.color.paletteIndex))
axis = state.entries.map { it.timestamp.toLocalDate() } axis = state.entries.map { it.timestamp.toLocalDate() }
} }

@ -22,6 +22,7 @@ package org.isoron.uhabits.core.ui.screens.habits.show.views
import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.countSkippedDays
import org.isoron.uhabits.core.models.groupedSum import org.isoron.uhabits.core.models.groupedSum
import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.views.Theme import org.isoron.uhabits.core.ui.views.Theme
@ -33,6 +34,7 @@ data class BarCardState(
val bucketSize: Int, val bucketSize: Int,
val color: PaletteColor, val color: PaletteColor,
val entries: List<Entry>, val entries: List<Entry>,
val skippedEntries: List<Entry>,
val isNumerical: Boolean, val isNumerical: Boolean,
val numericalSpinnerPosition: Int, val numericalSpinnerPosition: Int,
) )
@ -64,9 +66,17 @@ class BarCardPresenter(
firstWeekday = firstWeekday, firstWeekday = firstWeekday,
isNumerical = habit.isNumerical, isNumerical = habit.isNumerical,
) )
// get all data from the oldest date till today, then count skipped days, and
// finally group days according to the truncate value (by weeks for example)
val skippedEntries = habit.computedEntries.getByInterval(oldest, today).countSkippedDays(
truncateField = ScoreCardPresenter.getTruncateField(bucketSize),
firstWeekday = firstWeekday
)
return BarCardState( return BarCardState(
theme = theme, theme = theme,
entries = entries, entries = entries,
skippedEntries = skippedEntries,
bucketSize = bucketSize, bucketSize = bucketSize,
color = habit.color, color = habit.color,
isNumerical = habit.isNumerical, isNumerical = habit.isNumerical,

@ -36,6 +36,7 @@ class BarChart(
// Data // Data
var series = mutableListOf<List<Double>>() var series = mutableListOf<List<Double>>()
var skippedSeries = mutableListOf<List<Double>>()
var colors = mutableListOf<Color>() var colors = mutableListOf<Color>()
var axis = listOf<LocalDate>() var axis = listOf<LocalDate>()
override var dataOffset = 0 override var dataOffset = 0
@ -83,28 +84,64 @@ class BarChart(
dataColumn < 0 || dataColumn >= series[s].size -> 0.0 dataColumn < 0 || dataColumn >= series[s].size -> 0.0
else -> series[s][dataColumn] else -> series[s][dataColumn]
} }
if (value <= 0) return val skippedValue = when {
dataColumn < 0 || dataColumn >= series[s].size -> 0.0
else -> skippedSeries[s][dataColumn]
}
if (value <= 0 && skippedValue <= 0.0) return // no value to be drawn
val perc = value / maxValue val perc = value / maxValue
val skipPerc = skippedValue / maxValue
val barHeight = round(maxBarHeight * perc) val barHeight = round(maxBarHeight * perc)
val skipBarHeight = round(maxBarHeight * skipPerc)
val x = barOffset(c, s) val x = barOffset(c, s)
val y = height - footerHeight - barHeight val y = height - footerHeight - barHeight
val skipY = y - skipBarHeight
canvas.setColor(colors[s]) canvas.setColor(colors[s])
val r = round(barWidth * 0.15) val r = round(barWidth * 0.15)
if (2 * r < barHeight) { if (2 * r < barHeight) {
// draw the main column
canvas.fillRect(x, y + r, barWidth, barHeight - r) canvas.fillRect(x, y + r, barWidth, barHeight - r)
canvas.fillRect(x + r, y, barWidth - 2 * r, r + 1)
canvas.fillCircle(x + r, y + r, r)
canvas.fillCircle(x + barWidth - r, y + r, r)
} else { } else {
canvas.fillRect(x, y, barWidth, barHeight) canvas.fillRect(x, y, barWidth, barHeight)
} }
// draw the skipped part
if (skippedValue > 0) {
// make the skipped day square color lighter by the half
canvas.setColor(colors[s].blendWith(theme.cardBackgroundColor, 0.5))
// if only skipped days are drawn, no separation (r) space is needed anymore
val h = if (value <= 0) skipBarHeight - r
else skipBarHeight
canvas.fillRect(x, skipY + r, barWidth, h)
}
// draw a small (rect) on top of the column
// draw this before the skipped part to draw the grid above
val rectY: Double
if (skippedValue > 0) {
rectY = skipY
canvas.setColor(colors[s].blendWith(theme.cardBackgroundColor, 0.5))
} else {
rectY = y
canvas.setColor(colors[s])
}
canvas.fillRect(x + r, rectY, barWidth - 2 * r, r + 1)
// draw two circles to make the column top rounded on both sides
canvas.fillCircle(x + r, rectY + r, r)
canvas.fillCircle(x + barWidth - r, rectY + r, r)
// draw the number above the column
canvas.setFontSize(theme.smallTextSize) canvas.setFontSize(theme.smallTextSize)
canvas.setTextAlign(TextAlign.CENTER) canvas.setTextAlign(TextAlign.CENTER)
canvas.setColor(colors[s]) canvas.setColor(colors[s])
val textY: Double = if (skippedValue > 0) skipY
else y
val textValue = value + skippedValue
canvas.drawText( canvas.drawText(
value.toShortString(), textValue.toShortString(),
x + barWidth / 2, x + barWidth / 2,
y - theme.smallTextSize * 0.80 textY - theme.smallTextSize * 0.80
) )
} }

Loading…
Cancel
Save