Adds references to the functions for the buttons and ringView for the creation of most of the widget now. As well as fixes some logic in HabitListChart.

Also changes habit colors to DarkTheme for easier readability. Change the widget preview as well.
pull/2181/head
skippyy22 2 months ago
parent 98ec166666
commit dd324a8bda

@ -22,7 +22,6 @@ import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF import android.graphics.RectF
import android.graphics.Typeface import android.graphics.Typeface
import android.text.Layout import android.text.Layout
@ -30,31 +29,22 @@ import android.text.StaticLayout
import android.text.TextPaint import android.text.TextPaint
import android.text.TextUtils import android.text.TextUtils
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log
import android.view.View import android.view.View
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels
import org.isoron.uhabits.utils.InterfaceUtils.getDimension
import org.isoron.uhabits.utils.StyledResources import org.isoron.uhabits.utils.StyledResources
import kotlin.math.max import kotlin.math.max
import androidx.core.graphics.withTranslation import androidx.core.graphics.withTranslation
import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.activities.habits.list.views.toShortString
import org.isoron.uhabits.core.models.Entry.Companion.NO
import org.isoron.uhabits.core.models.Entry.Companion.SKIP
import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN
import org.isoron.uhabits.core.models.NumericalHabitType import org.isoron.uhabits.core.models.NumericalHabitType
import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST
import org.isoron.uhabits.core.models.NumericalHabitType.AT_MOST
import org.isoron.uhabits.core.ui.screens.habits.show.views.IndividualHabitListState import org.isoron.uhabits.core.ui.screens.habits.show.views.IndividualHabitListState
import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.dim
import kotlin.math.min import kotlin.math.min
import org.isoron.platform.gui.toInt import org.isoron.platform.gui.toInt
import org.isoron.uhabits.activities.habits.list.views.CheckmarkButtonView
import org.isoron.uhabits.activities.habits.list.views.NumberButtonView
import org.isoron.uhabits.utils.dp
private val BOLD_TYPEFACE = Typeface.create("sans-serif-condensed", Typeface.BOLD)
private val NORMAL_TYPEFACE = Typeface.create("sans-serif-condensed", Typeface.NORMAL)
class HabitListChart : View { class HabitListChart : View {
@ -66,15 +56,17 @@ class HabitListChart : View {
private var numCheckMarks = 0 private var numCheckMarks = 0
private var habitRowSize = 0 private var habitRowSize = 0
private var checkMarkSize = 18.dpToPx()
private var textBoxSize = checkMarkSize * 2
private var padding = dpToPixels(context, 4f) private var padding = dpToPixels(context, 4f)
private var scaleFactor = 25f private var checkMarkSize = dim(R.dimen.checkmarkWidth) * .85f
private var ringSize = 18.dpToPx()
private val minTextBoxWidth = dim(R.dimen.checkmarkWidth)
private var textBoxSize = minTextBoxWidth
private val rect = RectF() private val rect = RectF()
private val barRect = RectF() private val barRect = RectF()
private var backGroundPaint: Paint? = null private var backGroundPaint: Paint? = null
private var backGroundColor = 0
private var lowContrastTextColor = 0 // contrast20 private var lowContrastTextColor = 0 // contrast20
private var mediumContrastTextColor = 0 // contrast40 private var mediumContrastTextColor = 0 // contrast40
private var highContrastTextColor = 0 // contrast60 private var highContrastTextColor = 0 // contrast60
@ -95,27 +87,6 @@ class HabitListChart : View {
color = Color.WHITE color = Color.WHITE
} }
private val pText: TextPaint = TextPaint().apply {
textSize = (dim(R.dimen.regularTextSize) * 1.5).toFloat()
typeface = BOLD_TYPEFACE
textAlign = Paint.Align.CENTER
isAntiAlias = true
}
private val pNumber: TextPaint = TextPaint().apply {
textSize = dim(R.dimen.smallTextSize)
typeface = BOLD_TYPEFACE
isAntiAlias = true
textAlign = Paint.Align.CENTER
}
private val pUnit: TextPaint = TextPaint().apply {
textSize = getDimension(context, R.dimen.smallerTextSize)
typeface = NORMAL_TYPEFACE
isAntiAlias = true
textAlign = Paint.Align.CENTER
}
override fun onMeasure(widthSpec: Int, heightSpec: Int) { override fun onMeasure(widthSpec: Int, heightSpec: Int) {
// width // width
var widthSpec = widthSpec var widthSpec = widthSpec
@ -151,27 +122,22 @@ class HabitListChart : View {
// Amount of Checkmarks and the size of the habit text // Amount of Checkmarks and the size of the habit text
val firstCheckMarkWithPadding = checkMarkSize + (padding * 4) val ringSizeWithPadding = ringSize + (padding * 2.5)
val otherCheckMarkWithPadding = checkMarkSize + (padding * 8) val widthLeftOver = width - ringSizeWithPadding
fun getCheckMarkWithPadding(i: Int) = firstCheckMarkWithPadding + i * otherCheckMarkWithPadding
val ringSizeWithPadding = checkMarkSize + (padding * 1.5)
val rowPadding = padding * 2
val minTextBoxSize = checkMarkSize * 2 + padding
if (width < 150.dpToPx()) {
Log.e("JMO", "1")
if ((widthLeftOver - checkMarkSize - padding) < minTextBoxWidth) {
numCheckMarks = 1 numCheckMarks = 1
textBoxSize = (width - (rowPadding) - ( firstCheckMarkWithPadding ) - padding - (ringSizeWithPadding)).toFloat() textBoxSize = (width - checkMarkSize - padding - ringSizeWithPadding).toFloat()
} }
else { numCheckMarks = ((((width ) * 0.64) / checkMarkSize)).toInt()
Log.e("JMO", "2") textBoxSize = (widthLeftOver - (checkMarkSize * numCheckMarks)).toFloat()
numCheckMarks = ((((width + (padding * 4) - (rowPadding)) * 0.62) / otherCheckMarkWithPadding)).toInt() if (textBoxSize < minTextBoxWidth && numCheckMarks > 1) {
textBoxSize = (width - (rowPadding) - ( getCheckMarkWithPadding(numCheckMarks - 1) )- padding - (ringSizeWithPadding)).toFloat() numCheckMarks--
if (textBoxSize - otherCheckMarkWithPadding >= minTextBoxSize){ textBoxSize += checkMarkSize
numCheckMarks++
textBoxSize -= otherCheckMarkWithPadding
} }
else if (textBoxSize - checkMarkSize >= minTextBoxWidth * 1.5){
numCheckMarks++
textBoxSize -= checkMarkSize
} }
if (numCheckMarks > maxCheckMarks) if (numCheckMarks > maxCheckMarks)
numCheckMarks = maxCheckMarks numCheckMarks = maxCheckMarks
@ -179,10 +145,14 @@ class HabitListChart : View {
} }
private fun init() { private fun init() {
val res = StyledResources(context)
backGroundPaint = Paint() backGroundPaint = Paint()
backGroundPaint!!.textAlign = Paint.Align.CENTER backGroundPaint!!.textAlign = Paint.Align.CENTER
backGroundPaint!!.isAntiAlias = true backGroundPaint!!.isAntiAlias = true
val res = StyledResources(context) backGroundPaint!!.color = res.getColor(R.attr.cardBgColor)
backGroundColor = res.getColor(R.attr.cardBgColor)
lowContrastTextColor = res.getColor(R.attr.contrast20) lowContrastTextColor = res.getColor(R.attr.contrast20)
mediumContrastTextColor = res.getColor(R.attr.contrast40) mediumContrastTextColor = res.getColor(R.attr.contrast40)
highContrastTextColor = res.getColor(R.attr.contrast60) highContrastTextColor = res.getColor(R.attr.contrast60)
@ -225,13 +195,12 @@ class HabitListChart : View {
} }
val em = paint.measureText("m") val em = paint.measureText("m")
val checkMarkCenterX = ((padding * 4) + checkMarkSize/2)
val checkMarkCenterY = rect.centerY() val checkMarkCenterY = rect.centerY()
// Draw dates // Draw dates
repeat(numCheckMarks) { index -> repeat(numCheckMarks) { index ->
val centerX = rect.right - (checkMarkCenterX * (index + 1) + (padding * 4) * (index)) val centerX = rect.right - ((checkMarkSize * (index + 1)) - (checkMarkSize / 2f) + padding)
val y1 = checkMarkCenterY - 0.25 * em val y1 = checkMarkCenterY - 0.25 * em
val y2 = checkMarkCenterY + 1.25 * em val y2 = checkMarkCenterY + 1.25 * em
@ -256,7 +225,7 @@ class HabitListChart : View {
canvas.drawRoundRect(barRect, round, round, backGroundPaint!!) canvas.drawRoundRect(barRect, round, round, backGroundPaint!!)
// ScoreRing // ScoreRing
val ringSize = checkMarkSize.toInt() val ringSize = ringSize.toInt()
val ringCenterX = (rect.left + (padding * 1.5) + ringSize/2).toFloat() val ringCenterX = (rect.left + (padding * 1.5) + ringSize/2).toFloat()
val ringCenterY = rect.centerY() val ringCenterY = rect.centerY()
drawRingView( drawRingView(
@ -268,7 +237,6 @@ class HabitListChart : View {
) )
// CheckMarks // CheckMarks
val checkMarkCenterX = ((padding * 4) + checkMarkSize/2)
val checkMarkCenterY = rect.centerY() val checkMarkCenterY = rect.centerY()
for (index in 1..numCheckMarks) { // 1 , 2, 3 if numCheckMarks == 3 for (index in 1..numCheckMarks) { // 1 , 2, 3 if numCheckMarks == 3
@ -279,13 +247,13 @@ class HabitListChart : View {
} }
// Checkbox Rectangle // Checkbox Rectangle
val centerX = rect.right - ((checkMarkCenterX * index) + (padding * 4) * (index - 1)) val centerX = rect.right - ((checkMarkSize * index) - (checkMarkSize / 2f) + padding)
val centerY = checkMarkCenterY val centerY = checkMarkCenterY
val checkRect = RectF() val checkRect = RectF()
checkRect.set( checkRect.set(
centerX - checkMarkSize / 2f, centerX - (checkMarkSize / 2f), // + padding * 3),
centerY - checkMarkSize / 2f, centerY - checkMarkSize / 2f,
centerX + checkMarkSize / 2f, centerX + (checkMarkSize / 2f), // + padding * 3),
centerY + checkMarkSize / 2f centerY + checkMarkSize / 2f
) )
@ -320,10 +288,11 @@ class HabitListChart : View {
} }
// Draw habit name // Draw habit name
textPaint.color = habit.color.toInt() // Add color to name
drawAdaptiveText( drawAdaptiveText(
canvas = canvas, canvas = canvas,
text = habit.name, text = habit.name,
x = ringCenterX + ringSize/2 + padding, x = (ringCenterX + ringSize/2 + padding),
y = rect.top, y = rect.top,
width= textBoxSize.toInt(), // textAreaWidth, width= textBoxSize.toInt(), // textAreaWidth,
height = habitRowSize, height = habitRowSize,
@ -340,36 +309,23 @@ class HabitListChart : View {
percentage: Float, percentage: Float,
color: Int color: Int
) { ) {
val thickness = checkMarkSize * 0.22f canvas.withTranslation(centerX, centerY) {
val ringSize = dp(16f).toInt()
val bgPaint = Paint().apply { val scoreRing = RingView(context).apply {
this.color = Color.argb(25, Color.red(color), Color.green(color), Color.blue(color)) setThickness(dp(3.5f))
style = Paint.Style.STROKE setColor(color)
strokeWidth = thickness setPercentage(percentage)
isAntiAlias = true setIsTransparencyEnabled(true)
} }
val fgPaint = Paint().apply { scoreRing.measure(
this.color = color MeasureSpec.makeMeasureSpec(ringSize, MeasureSpec.EXACTLY),
style = Paint.Style.STROKE MeasureSpec.makeMeasureSpec(ringSize, MeasureSpec.EXACTLY)
strokeWidth = thickness
strokeCap = Paint.Cap.BUTT
isAntiAlias = true
}
val rect = RectF(
centerX - checkMarkSize / 2 + thickness / 2,
centerY - checkMarkSize / 2 + thickness / 2,
centerX - checkMarkSize / 2 + checkMarkSize - thickness / 2,
centerY - checkMarkSize / 2 + checkMarkSize - thickness / 2
) )
scoreRing.layout(0, 0, ringSize, ringSize)
// Draw background canvas.translate(-ringSize/2f, -ringSize/2f)
canvas.drawArc(rect, 0f, 360f, false, bgPaint) scoreRing.draw(canvas)
// Draw progress
if (percentage > 0) {
canvas.drawArc(rect, -90f, 360f * percentage, false, fgPaint)
} }
} }
@ -413,52 +369,20 @@ class HabitListChart : View {
targetType : NumericalHabitType, targetType : NumericalHabitType,
paint : Paint paint : Paint
) { ) {
// Color val button = NumberButtonView(context, preferences)
val activeColor = when {
value == SKIP.toDouble() / 1000 -> paint.color
value < 0.0 -> mediumContrastTextColor
(targetType == AT_LEAST) && (value >= threshold) -> paint.color
(targetType == AT_MOST) && (value <= threshold) -> paint.color
else -> highContrastTextColor
}
paint.color = activeColor
// Prepare text
val numberText = if (value >= 0) value.toShortString() else "0"
pNumber.color = activeColor button.value = value
pUnit.color = activeColor button.notes = ""
button.color = paint.color
button.targetType = targetType
button.threshold = threshold
button.units = units.substring(0, min(units.length, 7))
// Draw val buttonWidth = (checkMarkSize * 1.1f ).toInt()
val em = pNumber.measureText("m") button.layout(0, 0, buttonWidth, habitRowSize)
var questionMarkScale = 1.0
val verticalSpacing = em * 0.3f
if (units.isNotBlank()){ // if have units canvas.withTranslation(checkRect.centerX() - button.width / 2f, checkRect.centerY() - button.height / 2f) {
questionMarkScale = 0.8 button.draw(canvas)
checkRect.offset(0f, - verticalSpacing)
}
// Draw Number
when {
value == SKIP.toDouble() / 1000 -> {
drawSkipLine(canvas, checkRect, paint)
}
value >= 0 -> {
canvas.drawText(numberText,checkRect.centerX(),checkRect.centerY() + em / 3, pNumber)
}
preferences.areQuestionMarksEnabled -> {
drawSimpleText(canvas, checkRect, pNumber, "?", questionMarkScale)
}
else -> {
canvas.drawText(numberText,checkRect.centerX(),checkRect.centerY() + em / 3, pNumber)
}
}
// Draw Units
if (units.isNotBlank()) { // if have units
val unitsSub = units.substring(0, min(units.length, 7))
checkRect.offset(0f, +verticalSpacing + em)
canvas.drawText(unitsSub, checkRect.centerX(), checkRect.centerY() + em / 3, pUnit)
} }
} }
@ -469,139 +393,18 @@ class HabitListChart : View {
value: Int, value: Int,
paint: Paint) paint: Paint)
{ {
// Color
paint.color = when (value) {
YES_MANUAL, YES_AUTO, SKIP -> paint.color
NO -> {
if (preferences.areQuestionMarksEnabled) {
highContrastTextColor
} else {
mediumContrastTextColor
}
}
else -> mediumContrastTextColor
}
// Which CheckMark // Which CheckMark
when (value) { val button = CheckmarkButtonView(context, preferences)
SKIP -> drawSkipLine(canvas, checkRect, paint) button.value = value
NO -> drawXMark(canvas, checkRect, paint) button.notes = ""
UNKNOWN -> { button.color = paint.color
if (preferences.areQuestionMarksEnabled) {
drawSimpleText(canvas, checkRect, paint, "?")
} else {
drawXMark(canvas, checkRect, paint)
}
}
YES_AUTO -> {
drawCheckMark(canvas, checkRect, paint, false)
drawCheckMark(canvas, checkRect, paint, true)
}
else -> drawCheckMark(canvas, checkRect, paint)
}
}
private fun drawCheckMark(
canvas: Canvas,
checkRect: RectF,
paint: Paint,
isAuto: Boolean = false
) {
val scale = checkMarkSize / scaleFactor
canvas.withTranslation(checkRect.left , checkRect.top) {
scale(scale, scale)
// Draw Checkmark
val path = Path().apply {
moveTo(9f, 16.17f)
lineTo(4.83f, 12f)
lineTo(3.41f, 13.41f)
lineTo(9f, 19f)
lineTo(21f, 7f)
lineTo(19.59f, 5.59f)
close()
}
if (isAuto) {
// First draw: outline
paint.style = Paint.Style.STROKE
paint.strokeWidth = paint.strokeWidth // scale the stroke width
drawPath(path, paint)
// Second draw: inner fill
paint.style = Paint.Style.FILL
paint.color = mediumContrastTextColor // your background color
drawPath(path, paint)
} else {
// Regular checkmark
paint.style = Paint.Style.STROKE
drawPath(path, paint)
}
}
}
private fun drawSimpleText(
canvas: Canvas,
checkRect: RectF,
paint: Paint,
text: String,
scale: Double = 1.0
) {
pText.textSize = (dim(R.dimen.regularTextSize) * 1.5 * scale).toFloat()
pText.color = paint.color
val em = pText.measureText("m")
canvas.drawText(
text,
checkRect.centerX(),
checkRect.centerY() + em / 2,
pText
)
}
private fun drawSkipLine(
canvas: Canvas,
checkRect: RectF,
paint: Paint,
) {
val scale = checkMarkSize / scaleFactor
canvas.withTranslation(checkRect.left, checkRect.top) {
canvas.scale(scale, scale)
val lineWidth = 12f
val startX = 12f - lineWidth / 2
val endX = 12f + lineWidth / 2
val y = 12f
drawLine(startX, y, endX, y, paint)
}
canvas.withTranslation(checkRect.centerX() , checkRect.centerY()) {
button.draw(canvas)
} }
private fun drawXMark(
canvas: Canvas,
checkRect: RectF,
paint: Paint,
) {
val scale = checkMarkSize / scaleFactor
canvas.withTranslation(checkRect.left, checkRect.top) {
canvas.scale(scale, scale)
// Create the X path
val path = Path().apply {
moveTo(6f, 6f)
lineTo(18f, 18f)
moveTo(6f, 18f)
lineTo(18f, 6f)
}
canvas.drawPath(path, paint)
} }
}
fun setHabits(habits: List<IndividualHabitListState>) { fun setHabits(habits: List<IndividualHabitListState>) {
this.habits = habits this.habits = habits
requestLayout() requestLayout()

@ -28,7 +28,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.TextView import android.widget.TextView
import org.isoron.uhabits.activities.common.views.HabitListChart import org.isoron.uhabits.activities.common.views.HabitListChart
import org.isoron.uhabits.core.ui.screens.habits.show.views.HabitListCardPresenter import org.isoron.uhabits.core.ui.screens.habits.show.views.HabitListCardPresenter
import org.isoron.uhabits.core.ui.views.WidgetTheme import org.isoron.uhabits.core.ui.views.DarkTheme
import org.isoron.uhabits.widgets.views.GraphWidgetView import org.isoron.uhabits.widgets.views.GraphWidgetView
@ -49,7 +49,7 @@ class HabitListWidget(
val maxDays = 10 val maxDays = 10
val data = HabitListCardPresenter.buildState( val data = HabitListCardPresenter.buildState(
habits = habits, habits = habits,
theme = WidgetTheme(), theme = DarkTheme(),
maxDays = maxDays maxDays = maxDays
) )
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Loading…
Cancel
Save