HistoryChart: Fix transparency

pull/707/head
Alinson S. Xavier 5 years ago
parent 93a2ec3186
commit de3668db96

@ -26,8 +26,8 @@ import org.isoron.platform.gui.AndroidDataView
import org.isoron.platform.time.JavaLocalDateFormatter import org.isoron.platform.time.JavaLocalDateFormatter
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
import org.isoron.uhabits.core.ui.views.DarkTheme
import org.isoron.uhabits.core.ui.views.HistoryChart import org.isoron.uhabits.core.ui.views.HistoryChart
import org.isoron.uhabits.core.ui.views.WidgetTheme
import org.isoron.uhabits.core.utils.DateUtils import org.isoron.uhabits.core.utils.DateUtils
import org.isoron.uhabits.widgets.views.GraphWidgetView import org.isoron.uhabits.widgets.views.GraphWidgetView
import java.util.Locale import java.util.Locale
@ -51,7 +51,7 @@ class HistoryWidget(
habit = habit, habit = habit,
isSkipEnabled = prefs.isSkipEnabled, isSkipEnabled = prefs.isSkipEnabled,
firstWeekday = prefs.firstWeekday, firstWeekday = prefs.firstWeekday,
theme = DarkTheme(), theme = WidgetTheme(),
) )
(widgetView.dataView as AndroidDataView).apply { (widgetView.dataView as AndroidDataView).apply {
(this.view as HistoryChart).series = model.series (this.view as HistoryChart).series = model.series
@ -65,7 +65,7 @@ class HistoryWidget(
view = HistoryChart( view = HistoryChart(
today = DateUtils.getTodayWithOffset().toLocalDate(), today = DateUtils.getTodayWithOffset().toLocalDate(),
paletteColor = habit.color, paletteColor = habit.color,
theme = DarkTheme(), theme = WidgetTheme(),
dateFormatter = JavaLocalDateFormatter(Locale.getDefault()) dateFormatter = JavaLocalDateFormatter(Locale.getDefault())
) )
} }

@ -20,7 +20,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent" android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="#ffff00">
<org.isoron.platform.gui.AndroidTestView <org.isoron.platform.gui.AndroidTestView
android:layout_width="500dp" android:layout_width="500dp"

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@ -52,9 +52,16 @@ interface Canvas {
fun setTextAlign(align: TextAlign) fun setTextAlign(align: TextAlign)
fun toImage(): Image fun toImage(): Image
/**
* Fills entire canvas with the current color.
*/
fun fill() {
fillRect(0.0, 0.0, getWidth(), getHeight())
}
fun drawTestImage() { fun drawTestImage() {
// Draw grey background // Draw transparent background
setColor(Color(0x303030)) setColor(Color(0.1, 0.1, 0.1, 0.5))
fillRect(0.0, 0.0, 500.0, 400.0) fillRect(0.0, 0.0, 500.0, 400.0)
// Draw center rectangle // Draw center rectangle
@ -63,7 +70,7 @@ interface Canvas {
drawRect(100.0, 100.0, 300.0, 200.0) drawRect(100.0, 100.0, 300.0, 200.0)
// Draw squares, circles and arcs // Draw squares, circles and arcs
setColor(Color(0xFFFF00)) setColor(Color.YELLOW)
setStrokeWidth(1.0) setStrokeWidth(1.0)
drawRect(0.0, 0.0, 100.0, 100.0) drawRect(0.0, 0.0, 100.0, 100.0)
fillCircle(50.0, 50.0, 30.0) fillCircle(50.0, 50.0, 30.0)
@ -75,7 +82,7 @@ interface Canvas {
fillArc(50.0, 350.0, 30.0, 45.0, 90.0) fillArc(50.0, 350.0, 30.0, 45.0, 90.0)
// Draw two red crossing lines // Draw two red crossing lines
setColor(Color(0xFF0000)) setColor(Color.RED)
setStrokeWidth(2.0) setStrokeWidth(2.0)
drawLine(0.0, 0.0, 500.0, 400.0) drawLine(0.0, 0.0, 500.0, 400.0)
drawLine(500.0, 0.0, 0.0, 400.0) drawLine(500.0, 0.0, 0.0, 400.0)
@ -83,7 +90,7 @@ interface Canvas {
// Draw text // Draw text
setFont(Font.BOLD) setFont(Font.BOLD)
setFontSize(50.0) setFontSize(50.0)
setColor(Color(0x00FF00)) setColor(Color.GREEN)
setTextAlign(TextAlign.CENTER) setTextAlign(TextAlign.CENTER)
drawText("HELLO", 250.0, 100.0) drawText("HELLO", 250.0, 100.0)
setTextAlign(TextAlign.RIGHT) setTextAlign(TextAlign.RIGHT)

@ -23,9 +23,8 @@ data class Color(
val red: Double, val red: Double,
val green: Double, val green: Double,
val blue: Double, val blue: Double,
val alpha: Double val alpha: Double,
) { ) {
val luminosity: Double val luminosity: Double
get() { get() {
return 0.21 * red + 0.72 * green + 0.07 * blue return 0.21 * red + 0.72 * green + 0.07 * blue
@ -53,4 +52,18 @@ data class Color(
val relativeLuminosity = (l1 + 0.05) / (l2 + 0.05) val relativeLuminosity = (l1 + 0.05) / (l2 + 0.05)
return if (relativeLuminosity >= 1) relativeLuminosity else 1 / relativeLuminosity return if (relativeLuminosity >= 1) relativeLuminosity else 1 / relativeLuminosity
} }
fun withAlpha(newAlpha: Double) = Color(red, green, blue, newAlpha)
companion object {
val TRANSPARENT = Color(0.0, 0.0, 0.0, 0.0)
val RED = Color(1.0, 0.0, 0.0, 1.0)
val GREEN = Color(0.0, 1.0, 0.0, 1.0)
val BLUE = Color(1.0, 0.0, 1.0, 1.0)
val YELLOW = Color(1.0, 1.0, 0.0, 1.0)
val MAGENTA = Color(1.0, 0.0, 1.0, 1.0)
val CYAN = Color(0.0, 1.0, 1.0, 1.0)
val WHITE = Color(1.0, 1.0, 1.0, 1.0)
val BLACK = Color(0.0, 0.0, 0.0, 1.0)
}
} }

@ -49,7 +49,6 @@ class BarChart(
var barMargin = 3.0 var barMargin = 3.0
var barWidth = 12.0 var barWidth = 12.0
var nGridlines = 6 var nGridlines = 6
var backgroundColor = theme.cardBackgroundColor
override val dataColumnWidth: Double override val dataColumnWidth: Double
get() = barWidth + barMargin * 2 get() = barWidth + barMargin * 2
@ -67,8 +66,8 @@ class BarChart(
var maxValue = series.map { it.max()!! }.max()!! var maxValue = series.map { it.max()!! }.max()!!
maxValue = max(maxValue, 1.0) maxValue = max(maxValue, 1.0)
canvas.setColor(backgroundColor) canvas.setColor(theme.cardBackgroundColor)
canvas.fillRect(0.0, 0.0, width, height) canvas.fill()
fun barGroupOffset(c: Int) = marginLeft + paddingLeft + fun barGroupOffset(c: Int) = marginLeft + paddingLeft +
(c) * barGroupWidth (c) * barGroupWidth
@ -97,13 +96,6 @@ class BarChart(
canvas.fillCircle(x + barWidth - r, y + r, r) canvas.fillCircle(x + barWidth - r, y + r, r)
canvas.setFontSize(theme.smallTextSize) canvas.setFontSize(theme.smallTextSize)
canvas.setTextAlign(TextAlign.CENTER) canvas.setTextAlign(TextAlign.CENTER)
canvas.setColor(backgroundColor)
canvas.fillRect(
x - barMargin,
y - theme.smallTextSize * 1.25,
barWidth + 2 * barMargin,
theme.smallTextSize * 1.0
)
canvas.setColor(colors[s]) canvas.setColor(colors[s])
canvas.drawText( canvas.drawText(
value.toShortString(), value.toShortString(),
@ -119,12 +111,7 @@ class BarChart(
fun drawMajorGrid() { fun drawMajorGrid() {
canvas.setStrokeWidth(1.0) canvas.setStrokeWidth(1.0)
if (nSeries > 1) { if (nSeries > 1) {
canvas.setColor( canvas.setColor(theme.lowContrastTextColor.withAlpha(0.5))
backgroundColor.blendWith(
theme.lowContrastTextColor,
0.5
)
)
for (c in 0 until nColumns - 1) { for (c in 0 until nColumns - 1) {
val x = barGroupOffset(c) val x = barGroupOffset(c)
canvas.drawLine(x, paddingTop, x, paddingTop + maxBarHeight) canvas.drawLine(x, paddingTop, x, paddingTop + maxBarHeight)
@ -141,8 +128,6 @@ class BarChart(
fun drawAxis() { fun drawAxis() {
val y = paddingTop + maxBarHeight val y = paddingTop + maxBarHeight
canvas.setColor(backgroundColor)
canvas.fillRect(0.0, y, width, height - y)
canvas.setColor(theme.lowContrastTextColor) canvas.setColor(theme.lowContrastTextColor)
canvas.drawLine(0.0, y, width, y) canvas.drawLine(0.0, y, width, y)
canvas.setColor(theme.mediumContrastTextColor) canvas.setColor(theme.mediumContrastTextColor)

@ -33,7 +33,7 @@ class HistoryChart(
var today: LocalDate, var today: LocalDate,
var paletteColor: PaletteColor, var paletteColor: PaletteColor,
var theme: Theme, var theme: Theme,
var dateFormatter: LocalDateFormatter var dateFormatter: LocalDateFormatter,
) : DataView { ) : DataView {
enum class Square { enum class Square {
@ -61,8 +61,10 @@ class HistoryChart(
override fun draw(canvas: Canvas) { override fun draw(canvas: Canvas) {
val width = canvas.getWidth() val width = canvas.getWidth()
val height = canvas.getHeight() val height = canvas.getHeight()
canvas.setColor(theme.cardBackgroundColor) canvas.setColor(theme.cardBackgroundColor)
canvas.fillRect(0.0, 0.0, width, height) canvas.fill()
squareSize = round((height - 2 * padding) / 8.0) squareSize = round((height - 2 * padding) / 8.0)
canvas.setFontSize(height * 0.06) canvas.setFontSize(height * 0.06)
@ -98,7 +100,7 @@ class HistoryChart(
canvas: Canvas, canvas: Canvas,
column: Int, column: Int,
topDate: LocalDate, topDate: LocalDate,
topOffset: Int topOffset: Int,
) { ) {
drawHeader(canvas, column, topDate) drawHeader(canvas, column, topDate)
repeat(7) { row -> repeat(7) { row ->
@ -150,7 +152,7 @@ class HistoryChart(
width: Double, width: Double,
height: Double, height: Double,
date: LocalDate, date: LocalDate,
offset: Int offset: Int,
) { ) {
val value = if (offset >= series.size) Square.OFF else series[offset] val value = if (offset >= series.size) Square.OFF else series[offset]
@ -187,9 +189,13 @@ class HistoryChart(
} }
} }
val c1 = squareColor.contrast(theme.cardBackgroundColor) val textColor = if (theme.cardBackgroundColor == Color.TRANSPARENT) {
val c2 = squareColor.contrast(theme.mediumContrastTextColor) theme.highContrastTextColor
val textColor = if (c1 > c2) theme.cardBackgroundColor else theme.mediumContrastTextColor } else {
val c1 = squareColor.contrast(theme.cardBackgroundColor)
val c2 = squareColor.contrast(theme.mediumContrastTextColor)
if (c1 > c2) theme.cardBackgroundColor else theme.mediumContrastTextColor
}
canvas.setColor(textColor) canvas.setColor(textColor)
canvas.setTextAlign(TextAlign.CENTER) canvas.setTextAlign(TextAlign.CENTER)

@ -66,9 +66,9 @@ abstract class Theme {
val regularTextSize = 17.0 val regularTextSize = 17.0
} }
class LightTheme : Theme() open class LightTheme : Theme()
class DarkTheme : Theme() { open class DarkTheme : Theme() {
override val appBackgroundColor = Color(0x212121) override val appBackgroundColor = Color(0x212121)
override val cardBackgroundColor = Color(0x303030) override val cardBackgroundColor = Color(0x303030)
override val headerBackgroundColor = Color(0x212121) override val headerBackgroundColor = Color(0x212121)
@ -108,3 +108,10 @@ class DarkTheme : Theme() {
} }
} }
} }
class WidgetTheme : LightTheme() {
override val cardBackgroundColor = Color.TRANSPARENT
override val highContrastTextColor = Color.WHITE
override val mediumContrastTextColor = Color.WHITE.withAlpha(0.50)
override val lowContrastTextColor = Color.WHITE.withAlpha(0.10)
}

@ -46,6 +46,18 @@ class BarChartTest {
assertRenders(300, 200, "$base/base.png", component) assertRenders(300, 200, "$base/base.png", component)
} }
@Test
fun testDrawDarkTheme() = runBlocking {
component.theme = DarkTheme()
assertRenders(300, 200, "$base/themeDark.png", component)
}
@Test
fun testDrawWidgetTheme() = runBlocking {
component.theme = WidgetTheme()
assertRenders(300, 200, "$base/themeWidget.png", component)
}
@Test @Test
fun testDrawWithOffset() = runBlocking { fun testDrawWithOffset() = runBlocking {
component.dataOffset = 5 component.dataOffset = 5

@ -31,6 +31,7 @@ import org.isoron.uhabits.core.ui.views.HistoryChart.Square.HATCHED
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.OFF import org.isoron.uhabits.core.ui.views.HistoryChart.Square.OFF
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.ON import org.isoron.uhabits.core.ui.views.HistoryChart.Square.ON
import org.isoron.uhabits.core.ui.views.LightTheme import org.isoron.uhabits.core.ui.views.LightTheme
import org.isoron.uhabits.core.ui.views.WidgetTheme
import org.junit.Test import org.junit.Test
import java.util.Locale import java.util.Locale
@ -70,7 +71,6 @@ class HistoryChartTest {
} }
// TODO: Label overflow // TODO: Label overflow
// TODO: Transparent
// TODO: onClick // TODO: onClick
// TODO: HistoryEditorDialog // TODO: HistoryEditorDialog
// TODO: Remove excessive padding on widgets // TODO: Remove excessive padding on widgets
@ -89,7 +89,13 @@ class HistoryChartTest {
@Test @Test
fun testDrawDarkTheme() = runBlocking { fun testDrawDarkTheme() = runBlocking {
view.theme = DarkTheme() view.theme = DarkTheme()
assertRenders(400, 200, "$base/dark.png", view) assertRenders(400, 200, "$base/themeDark.png", view)
}
@Test
fun testDrawWidgetTheme() = runBlocking {
view.theme = WidgetTheme()
assertRenders(400, 200, "$base/themeWidget.png", view)
} }
@Test @Test

Loading…
Cancel
Save