kopia lustrzana https://github.com/ryukoposting/Signal-Android
150 wiersze
4.2 KiB
Kotlin
150 wiersze
4.2 KiB
Kotlin
package org.signal.imageeditor.core.renderers
|
|
|
|
import android.graphics.Color
|
|
import android.graphics.Paint
|
|
import android.graphics.RectF
|
|
import android.graphics.drawable.Drawable
|
|
import android.os.Parcel
|
|
import android.os.Parcelable
|
|
import android.view.animation.Interpolator
|
|
import androidx.appcompat.content.res.AppCompatResources
|
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
|
import org.signal.core.util.DimensionUnit
|
|
import org.signal.imageeditor.R
|
|
import org.signal.imageeditor.core.Bounds
|
|
import org.signal.imageeditor.core.Renderer
|
|
import org.signal.imageeditor.core.RendererContext
|
|
|
|
internal class TrashRenderer : InvalidateableRenderer, Renderer, Parcelable {
|
|
|
|
private val outlinePaint = Paint().apply {
|
|
isAntiAlias = true
|
|
color = Color.WHITE
|
|
style = Paint.Style.STROKE
|
|
strokeWidth = DimensionUnit.DP.toPixels(1.5f)
|
|
}
|
|
|
|
private val shadePaint = Paint().apply {
|
|
isAntiAlias = true
|
|
color = 0x99000000.toInt()
|
|
style = Paint.Style.FILL
|
|
}
|
|
|
|
private val bounds = RectF()
|
|
|
|
private val diameterSmall = DimensionUnit.DP.toPixels(41f)
|
|
private val diameterLarge = DimensionUnit.DP.toPixels(54f)
|
|
private val trashSize: Int = DimensionUnit.DP.toPixels(24f).toInt()
|
|
private val padBottom = DimensionUnit.DP.toPixels(16f)
|
|
private val interpolator: Interpolator = FastOutSlowInInterpolator()
|
|
|
|
private var startTime = 0L
|
|
|
|
private var isExpanding = false
|
|
|
|
private val buttonCenter = FloatArray(2)
|
|
|
|
constructor()
|
|
|
|
override fun render(rendererContext: RendererContext) {
|
|
super.render(rendererContext)
|
|
|
|
val frameRenderTime = System.currentTimeMillis()
|
|
|
|
val trash: Drawable = requireNotNull(AppCompatResources.getDrawable(rendererContext.context, R.drawable.ic_trash_white_24))
|
|
trash.setBounds(0, 0, trashSize, trashSize)
|
|
|
|
val diameter = getInterpolatedDiameter(frameRenderTime - startTime)
|
|
|
|
rendererContext.canvas.save()
|
|
rendererContext.mapRect(bounds, Bounds.FULL_BOUNDS)
|
|
|
|
buttonCenter[0] = bounds.centerX()
|
|
buttonCenter[1] = bounds.bottom - diameterLarge / 2f - padBottom
|
|
|
|
rendererContext.canvasMatrix.setToIdentity()
|
|
|
|
rendererContext.canvas.drawCircle(buttonCenter[0], buttonCenter[1], diameter / 2f, shadePaint)
|
|
rendererContext.canvas.drawCircle(buttonCenter[0], buttonCenter[1], diameter / 2f, outlinePaint)
|
|
rendererContext.canvas.translate(bounds.centerX(), bounds.bottom - diameterLarge / 2f - padBottom)
|
|
rendererContext.canvas.translate(-(trashSize / 2f), -(trashSize / 2f))
|
|
trash.draw(rendererContext.canvas)
|
|
rendererContext.canvas.restore()
|
|
|
|
if (frameRenderTime - DURATION < startTime) {
|
|
invalidate()
|
|
}
|
|
}
|
|
|
|
private fun getInterpolatedDiameter(timeElapsed: Long): Float {
|
|
return if (timeElapsed >= DURATION) {
|
|
if (isExpanding) {
|
|
diameterLarge
|
|
} else {
|
|
diameterSmall
|
|
}
|
|
} else {
|
|
val interpolatedFraction = interpolator.getInterpolation(timeElapsed / DURATION.toFloat())
|
|
if (isExpanding) {
|
|
interpolateFromFraction(interpolatedFraction)
|
|
} else {
|
|
interpolateFromFraction(1 - interpolatedFraction)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun interpolateFromFraction(fraction: Float): Float {
|
|
return diameterSmall + (diameterLarge - diameterSmall) * fraction
|
|
}
|
|
|
|
fun expand() {
|
|
if (isExpanding) {
|
|
return
|
|
}
|
|
|
|
isExpanding = true
|
|
startTime = System.currentTimeMillis()
|
|
invalidate()
|
|
}
|
|
|
|
fun shrink() {
|
|
if (!isExpanding) {
|
|
return
|
|
}
|
|
|
|
isExpanding = false
|
|
startTime = System.currentTimeMillis()
|
|
invalidate()
|
|
}
|
|
|
|
override fun hitTest(x: Float, y: Float): Boolean {
|
|
val dx = x - buttonCenter[0]
|
|
val dy = y - buttonCenter[1]
|
|
val radius = diameterLarge / 2
|
|
|
|
return dx * dx + dy * dy < radius * radius
|
|
}
|
|
|
|
override fun describeContents(): Int {
|
|
return 0
|
|
}
|
|
|
|
override fun writeToParcel(dest: Parcel, flags: Int) {}
|
|
|
|
companion object {
|
|
|
|
private const val DURATION = 150L
|
|
|
|
@JvmField
|
|
val CREATOR: Parcelable.Creator<TrashRenderer> = object : Parcelable.Creator<TrashRenderer> {
|
|
override fun createFromParcel(`in`: Parcel): TrashRenderer {
|
|
return TrashRenderer()
|
|
}
|
|
|
|
override fun newArray(size: Int): Array<TrashRenderer?> {
|
|
return arrayOfNulls(size)
|
|
}
|
|
}
|
|
}
|
|
}
|