Copy platform.{gui,io,time} from core; implement AndroidCanvas

This commit is contained in:
2020-12-31 13:29:06 -06:00
parent 13826f4934
commit e97cdce467
44 changed files with 1996 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.platform.gui
import android.graphics.Bitmap
import org.isoron.uhabits.BaseViewTest
import org.junit.Test
class AndroidCanvasTest : BaseViewTest() {
@Test
fun testDrawTestImage() {
similarityCutoff = 0.0005
val bmp = Bitmap.createBitmap(1000, 800, Bitmap.Config.ARGB_8888)
val canvas = AndroidCanvas()
canvas.context = testContext
canvas.density = 2.0
canvas.innerCanvas = android.graphics.Canvas(bmp)
canvas.innerBitmap = bmp
canvas.drawTestImage()
assertRenders(bmp, "CanvasTest.png")
}
}

View File

@@ -47,11 +47,14 @@ public class BaseViewTest extends BaseAndroidTest
protected void assertRenders(View view, String expectedImagePath)
throws IOException
{
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
expectedImagePath = "views/" + expectedImagePath;
Bitmap actual = renderView(view);
if(actual == null) throw new IllegalStateException("actual is null");
assertRenders(actual, expectedImagePath);
}
protected void assertRenders(Bitmap actual, String expectedImagePath) throws IOException {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
expectedImagePath = "views/" + expectedImagePath;
try
{
Bitmap expected = getBitmapFromAssets(expectedImagePath);
@@ -145,7 +148,7 @@ public class BaseViewTest extends BaseAndroidTest
}
}
distance /= (0xff * 16) * b1.getWidth() * b1.getHeight();
distance /= 255.0 * 16 * b1.getWidth() * b1.getHeight();
return distance;
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.platform.gui
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.text.TextPaint
import android.util.AttributeSet
import android.view.View
import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome
class AndroidCanvas : Canvas {
lateinit var innerCanvas: android.graphics.Canvas
lateinit var context: Context
var innerBitmap: Bitmap? = null
var density = 1.0
var paint = Paint().apply {
isAntiAlias = true
}
var textPaint = TextPaint().apply {
isAntiAlias = true
}
var textBounds = Rect()
private fun Double.toDp() = (this * density).toFloat()
override fun setColor(color: Color) {
paint.color = color.toInt()
textPaint.color = color.toInt()
}
override fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) {
innerCanvas.drawLine(
x1.toDp(),
y1.toDp(),
x2.toDp(),
y2.toDp(),
paint,
)
}
override fun drawText(text: String, x: Double, y: Double) {
textPaint.getTextBounds(text, 0, text.length, textBounds)
innerCanvas.drawText(
text,
x.toDp(),
y.toDp() - textBounds.exactCenterY(),
textPaint,
)
}
override fun fillRect(x: Double, y: Double, width: Double, height: Double) {
paint.style = Paint.Style.FILL
rect(x, y, width, height)
}
override fun drawRect(x: Double, y: Double, width: Double, height: Double) {
paint.style = Paint.Style.STROKE
rect(x, y, width, height)
}
private fun rect(x: Double, y: Double, width: Double, height: Double) {
innerCanvas.drawRect(
x.toDp(),
y.toDp(),
(x + width).toDp(),
(y + height).toDp(),
paint,
)
}
override fun getHeight(): Double {
return innerCanvas.height / density
}
override fun getWidth(): Double {
return innerCanvas.width / density
}
override fun setFont(font: Font) {
textPaint.typeface = when (font) {
Font.REGULAR -> Typeface.DEFAULT
Font.BOLD -> Typeface.DEFAULT_BOLD
Font.FONT_AWESOME -> getFontAwesome(context)
}
}
override fun setFontSize(size: Double) {
textPaint.textSize = size.toDp() * 1.07f
}
override fun setStrokeWidth(size: Double) {
paint.strokeWidth = size.toDp()
}
override fun fillArc(
centerX: Double,
centerY: Double,
radius: Double,
startAngle: Double,
swipeAngle: Double,
) {
paint.style = Paint.Style.FILL
innerCanvas.drawArc(
(centerX - radius).toDp(),
(centerY - radius).toDp(),
(centerX + radius).toDp(),
(centerY + radius).toDp(),
-startAngle.toFloat(),
-swipeAngle.toFloat(),
true,
paint,
)
}
override fun fillCircle(
centerX: Double,
centerY: Double,
radius: Double,
) {
paint.style = Paint.Style.FILL
innerCanvas.drawCircle(centerX.toDp(), centerY.toDp(), radius.toDp(), paint)
}
override fun setTextAlign(align: TextAlign) {
textPaint.textAlign = when (align) {
TextAlign.LEFT -> Paint.Align.LEFT
TextAlign.CENTER -> Paint.Align.CENTER
TextAlign.RIGHT -> Paint.Align.RIGHT
}
}
override fun toImage(): Image {
val bmp = innerBitmap ?: throw UnsupportedOperationException()
return AndroidImage(bmp)
}
}
class AndroidCanvasTestView(context: Context, attrs: AttributeSet) : View(context, attrs) {
val canvas = AndroidCanvas()
override fun onDraw(canvas: android.graphics.Canvas) {
this.canvas.context = context
this.canvas.innerCanvas = canvas
this.canvas.density = resources.displayMetrics.density.toDouble()
this.canvas.drawTestImage()
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.platform.gui
import android.graphics.Bitmap
import kotlin.math.roundToInt
class AndroidImage(private val bmp: Bitmap) : Image {
override val width: Int
get() = bmp.width
override val height: Int
get() = bmp.height
override fun getPixel(x: Int, y: Int): Color {
return Color(bmp.getPixel(x, y))
}
override fun setPixel(x: Int, y: Int, color: Color) {
bmp.setPixel(x, y, color.toInt())
}
override suspend fun export(path: String) {
TODO("Not yet implemented")
}
}
public fun Color.toInt(): Int {
return android.graphics.Color.argb(
(255 * this.alpha).roundToInt(),
(255 * this.red).roundToInt(),
(255 * this.green).roundToInt(),
(255 * this.blue).roundToInt(),
)
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
~
~ This file is part of Loop Habit Tracker.
~
~ Loop Habit Tracker is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by the
~ Free Software Foundation, either version 3 of the License, or (at your
~ option) any later version.
~
~ Loop Habit Tracker is distributed in the hope that it will be useful, but
~ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
~ more details.
~
~ You should have received a copy of the GNU General Public License along
~ with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<org.isoron.platform.gui.AndroidCanvasTestView
android:layout_width="500dp"
android:layout_height="400dp" />
</LinearLayout>