2017-08-25 20:24:25 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Christian Basler
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package ch.dissem.apps.abit
|
|
|
|
|
|
|
|
import android.graphics.*
|
|
|
|
import android.graphics.drawable.Drawable
|
2018-03-05 09:48:49 +01:00
|
|
|
import android.support.annotation.ColorInt
|
2017-08-25 20:24:25 +02:00
|
|
|
import android.text.TextPaint
|
|
|
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
2018-03-05 09:48:49 +01:00
|
|
|
import org.jetbrains.anko.collections.forEachWithIndex
|
|
|
|
import kotlin.math.sqrt
|
2017-08-25 20:24:25 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Christian Basler
|
|
|
|
*/
|
|
|
|
class Identicon(input: BitmessageAddress) : Drawable() {
|
|
|
|
|
|
|
|
private val paint = Paint().apply {
|
|
|
|
style = Paint.Style.FILL
|
|
|
|
isAntiAlias = true
|
|
|
|
}
|
|
|
|
private val hash = input.ripe
|
|
|
|
private val isChan = input.isChan
|
|
|
|
private val fields = Array(SIZE) { BooleanArray(SIZE) }.apply {
|
|
|
|
for (row in 0 until SIZE) {
|
|
|
|
if (!isChan || row < 5 || row > 6) {
|
|
|
|
for (column in 0..CENTER_COLUMN) {
|
|
|
|
if ((row - SIZE / 2) * (row - SIZE / 2) + (column - SIZE / 2) * (column - SIZE / 2) < SIZE / 2 * SIZE / 2) {
|
|
|
|
this[row][column] = hash[(row * CENTER_COLUMN + column) % hash.size] >= 0
|
|
|
|
this[row][SIZE - column - 1] = this[row][column]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-05 09:48:49 +01:00
|
|
|
private val color = Color.HSVToColor(
|
|
|
|
floatArrayOf(
|
|
|
|
(Math.abs(hash[0] * hash[1] + hash[2]) % 360).toFloat(),
|
|
|
|
0.8f,
|
|
|
|
1.0f
|
|
|
|
)
|
|
|
|
)
|
|
|
|
private val background = Color.HSVToColor(
|
|
|
|
floatArrayOf(
|
|
|
|
(Math.abs(hash[1] * hash[2] + hash[0]) % 360).toFloat(),
|
|
|
|
0.8f,
|
|
|
|
1.0f
|
|
|
|
)
|
|
|
|
)
|
2017-08-25 20:24:25 +02:00
|
|
|
private val textPaint = TextPaint().apply {
|
|
|
|
textAlign = Paint.Align.CENTER
|
|
|
|
color = 0xFF607D8B.toInt()
|
|
|
|
typeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun draw(canvas: Canvas) {
|
|
|
|
val width = canvas.width.toFloat()
|
|
|
|
val height = canvas.height.toFloat()
|
2018-03-05 09:48:49 +01:00
|
|
|
draw(canvas, 0f, 0f, width, height)
|
|
|
|
}
|
|
|
|
|
|
|
|
internal fun draw(canvas: Canvas, offsetX: Float, offsetY: Float, width: Float, height: Float) {
|
|
|
|
var x: Float
|
|
|
|
var y: Float
|
2017-08-25 20:24:25 +02:00
|
|
|
val cellWidth = width / SIZE.toFloat()
|
|
|
|
val cellHeight = height / SIZE.toFloat()
|
|
|
|
paint.color = background
|
2018-03-05 09:48:49 +01:00
|
|
|
canvas.drawCircle(offsetX + width / 2, offsetY + height / 2, width / 2, paint)
|
2017-08-25 20:24:25 +02:00
|
|
|
paint.color = color
|
|
|
|
for (row in 0 until SIZE) {
|
|
|
|
for (column in 0 until SIZE) {
|
|
|
|
if (fields[row][column]) {
|
2018-03-05 09:48:49 +01:00
|
|
|
x = offsetX + cellWidth * column
|
|
|
|
y = offsetY + cellHeight * row
|
2017-08-25 20:24:25 +02:00
|
|
|
canvas.drawCircle(
|
2018-03-05 09:48:49 +01:00
|
|
|
x + cellWidth / 2, y + cellHeight / 2, cellHeight / 2,
|
|
|
|
paint
|
2017-08-25 20:24:25 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isChan) {
|
|
|
|
textPaint.textSize = 2 * cellHeight
|
2018-03-05 09:48:49 +01:00
|
|
|
canvas.drawText("[isChan]", offsetX + width / 2, offsetY + 6.7f * cellHeight, textPaint)
|
2017-08-25 20:24:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun setAlpha(alpha: Int) {
|
|
|
|
paint.alpha = alpha
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun setColorFilter(cf: ColorFilter?) {
|
|
|
|
paint.colorFilter = cf
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun getOpacity() = PixelFormat.TRANSPARENT
|
|
|
|
|
|
|
|
companion object {
|
2018-02-20 16:40:03 +01:00
|
|
|
private const val SIZE = 9
|
|
|
|
private const val CENTER_COLUMN = 5
|
2017-08-25 20:24:25 +02:00
|
|
|
}
|
|
|
|
}
|
2018-03-05 09:48:49 +01:00
|
|
|
|
|
|
|
class MultiIdenticon(input: List<BitmessageAddress>, @ColorInt val backgroundColor: Int = Color.WHITE) :
|
|
|
|
Drawable() {
|
|
|
|
|
|
|
|
private val paint = Paint().apply {
|
|
|
|
style = Paint.Style.FILL
|
|
|
|
isAntiAlias = true
|
|
|
|
color = backgroundColor
|
|
|
|
}
|
|
|
|
|
2018-03-18 07:00:21 +01:00
|
|
|
private val identicons = input.map { Identicon(it) }.take(4)
|
2018-03-05 09:48:49 +01:00
|
|
|
|
|
|
|
override fun draw(canvas: Canvas) {
|
|
|
|
val width = canvas.width.toFloat()
|
|
|
|
val height = canvas.height.toFloat()
|
|
|
|
|
|
|
|
when (identicons.size) {
|
|
|
|
0 -> canvas.drawCircle(width / 2, height / 2, width / 2, paint)
|
2018-03-18 07:00:21 +01:00
|
|
|
1 -> identicons.first().draw(canvas, 0f, 0f, width, height)
|
2018-03-05 09:48:49 +01:00
|
|
|
2 -> {
|
|
|
|
canvas.drawCircle(width / 2, height / 2, width / 2, paint)
|
|
|
|
val w = width / 2
|
|
|
|
val h = height / 2
|
|
|
|
var x = 0f
|
|
|
|
val y = height / 4
|
|
|
|
identicons.forEach {
|
|
|
|
it.draw(canvas, x, y, w, h)
|
|
|
|
x += w
|
|
|
|
}
|
|
|
|
}
|
|
|
|
3 -> {
|
|
|
|
val scale = 1f / (1f + 2f * sqrt(3f))
|
|
|
|
val w = width * scale
|
|
|
|
val h = height * scale
|
|
|
|
|
|
|
|
identicons[0].draw(canvas, (width - w) / 2, 0f, w, h)
|
|
|
|
identicons[1].draw(canvas, (width - 2 * w) / 2, h * sqrt(3f) / 2, w, h)
|
|
|
|
identicons[2].draw(canvas, width / 2, h * sqrt(3f) / 2, w, h)
|
|
|
|
}
|
|
|
|
4 -> {
|
|
|
|
canvas.drawCircle(width / 2, height / 2, width / 2, paint)
|
|
|
|
val scale = 1f / (1f + sqrt(2f))
|
|
|
|
val borderScale = 0.5f - scale
|
|
|
|
val w = width * scale
|
|
|
|
val h = height * scale
|
|
|
|
val x = width * borderScale
|
|
|
|
val y = height * borderScale
|
|
|
|
identicons.forEachWithIndex { i, identicon ->
|
|
|
|
identicon.draw(canvas, x + (i % 2) * w, y + (i / 2) * h, w, h)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun setAlpha(alpha: Int) {
|
|
|
|
identicons.forEach { it.alpha = alpha }
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun setColorFilter(colorFilter: ColorFilter?) {
|
|
|
|
identicons.forEach { it.colorFilter = colorFilter }
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun getOpacity() = PixelFormat.TRANSPARENT
|
|
|
|
}
|