Skip to content

Commit

Permalink
Finish beta version development
Browse files Browse the repository at this point in the history
  • Loading branch information
l7naive committed May 30, 2018
1 parent a8f6985 commit 24a7ff9
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 39 deletions.
59 changes: 50 additions & 9 deletions library/src/main/java/com/itsxtt/patternlock/Cell.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package com.itsxtt.patternlock
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Point
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.util.Log
import android.view.View

//TODO: internal has no effect, still accessible outside the module
internal class Cell(context: Context,
var index: Int,
private var regularCellBackground: Drawable?,
Expand All @@ -24,10 +23,13 @@ internal class Cell(context: Context,
private var lineStyle: Int,
private var regularLineColor: Int,
private var errorLineColor: Int,
private var columnCount: Int) : View(context) {
private var columnCount: Int,
private var indicatorSizeRatio: Float) : View(context) {

private var currentState: State = State.REGULAR
private var paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
private var currentDegree: Float = -1f
private var indicatorPath: Path = Path()

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var cellWidth = MeasureSpec.getSize(widthMeasureSpec) / columnCount
Expand All @@ -36,23 +38,18 @@ internal class Cell(context: Context,
}

override fun onDraw(canvas: Canvas?) {
logg("Cell=>onDraw")
when(currentState) {
State.REGULAR -> drawDot(canvas, regularCellBackground, regularDotColor, regularDotRadiusRatio)
State.SELECTED -> drawDot(canvas, selectedCellBackground, selectedDotColor, selectedDotRadiusRatio)
State.ERROR -> drawDot(canvas, errorCellBackground, errorDotColor, errorDotRadiusRatio)
}
}

fun logg(log: String) {
Log.d("plv_", log)
}

private fun drawDot(canvas: Canvas?,
background: Drawable?,
dotColor: Int,
radiusRation: Float) {
var radius = (Math.min(width, height) - (paddingLeft + paddingRight)) / 2
var radius = getRadius()
var centerX = width / 2
var centerY = height / 2

Expand All @@ -68,6 +65,41 @@ internal class Cell(context: Context,
paint.color = dotColor
paint.style = Paint.Style.FILL
canvas?.drawCircle(centerX.toFloat(), centerY.toFloat(), radius * radiusRation, paint)

if (lineStyle == PatternLockView.LINE_STYLE_INDICATOR &&
(currentState == State.SELECTED || currentState == State.ERROR)) {
drawIndicator(canvas)
}
}

private fun drawIndicator(canvas: Canvas?) {
if (currentDegree != -1f) {
if (indicatorPath.isEmpty) {
indicatorPath.fillType = Path.FillType.WINDING
val radius = getRadius()
val height = radius * indicatorSizeRatio
indicatorPath.moveTo((width / 2).toFloat() , radius * (1 - selectedDotRadiusRatio - indicatorSizeRatio) / 2 + paddingTop)
indicatorPath.lineTo((width /2).toFloat() - height, radius * (1 - selectedDotRadiusRatio - indicatorSizeRatio) / 2 + height + paddingTop)
indicatorPath.lineTo((width / 2).toFloat() + height, radius * (1 - selectedDotRadiusRatio - indicatorSizeRatio) / 2 + height + paddingTop)
indicatorPath.close()
}

if (currentState == State.SELECTED) {
paint.color = regularLineColor
} else {
paint.color = errorLineColor
}
paint.style = Paint.Style.FILL

canvas?.save()
canvas?.rotate(currentDegree, (width / 2).toFloat(), (height / 2).toFloat())
canvas?.drawPath(indicatorPath, paint)
canvas?.restore()
}
}

fun getRadius() : Int {
return (Math.min(width, height) - (paddingLeft + paddingRight)) / 2
}


Expand All @@ -83,4 +115,13 @@ internal class Cell(context: Context,
invalidate()
}

fun setDegree(degree: Float) {
currentDegree = degree
}

fun reset() {
setState(State.REGULAR)
currentDegree = -1f
}

}
151 changes: 122 additions & 29 deletions library/src/main/java/com/itsxtt/patternlock/PatternLockView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.graphics.*
import android.graphics.drawable.Drawable
import android.support.v4.content.ContextCompat
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
Expand All @@ -21,6 +20,12 @@ class PatternLockView : GridLayout {
const val DEFAULT_SPACING = 24f // unit: dp
const val DEFAULT_ROW_COUNT = 3
const val DEFAULT_COLUMN_COUNT = 3
const val DEFAULT_ERROR_DURATION = 400 // unit: ms
const val DEFAULT_HIT_AREA_PADDING_RATIO = 0.2f
const val DEFAULT_INDICATOR_SIZE_RATIO = 0.25f

const val LINE_STYLE_COMMON = 1
const val LINE_STYLE_INDICATOR = 2
}

private var regularCellBackground: Drawable? = null
Expand All @@ -39,6 +44,7 @@ class PatternLockView : GridLayout {
* determine the line's style
* common: 1
* with indicator: 2
* invisible: 3
*/
private var lineStyle: Int = 0

Expand All @@ -51,6 +57,10 @@ class PatternLockView : GridLayout {
private var plvRowCount: Int = 0
private var plvColumnCount: Int = 0

private var errorDuration: Int = 0
private var hitAreaPaddingRatio: Float = 0f
private var indicatorSizeRatio: Float = 0f

private var cells: ArrayList<Cell> = ArrayList()
private var selectedCells: ArrayList<Cell> = ArrayList()

Expand All @@ -60,6 +70,10 @@ class PatternLockView : GridLayout {
private var lastX: Float = 0f
private var lastY: Float = 0f

private var isSecureMode = false

private var onPatternListener: OnPatternListener? = null

constructor(context: Context) : super(context)

constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
Expand Down Expand Up @@ -88,6 +102,10 @@ class PatternLockView : GridLayout {
plvRowCount = ta.getInteger(R.styleable.PatternLockView_plv_rowCount, DEFAULT_ROW_COUNT)
plvColumnCount = ta.getInteger(R.styleable.PatternLockView_plv_columnCount, DEFAULT_COLUMN_COUNT)

errorDuration = ta.getInteger(R.styleable.PatternLockView_plv_errorDuration, DEFAULT_ERROR_DURATION)
hitAreaPaddingRatio = ta.getFloat(R.styleable.PatternLockView_plv_hitAreaPaddingRatio, DEFAULT_HIT_AREA_PADDING_RATIO)
indicatorSizeRatio = ta.getFloat(R.styleable.PatternLockView_plv_indicatorSizeRatio, DEFAULT_INDICATOR_SIZE_RATIO)

ta.recycle()

rowCount = plvRowCount
Expand All @@ -104,12 +122,13 @@ class PatternLockView : GridLayout {
if (hitCell == null) {
return false
} else {
onPatternListener?.onStarted()
notifyCellSelected(hitCell)
}
}
MotionEvent.ACTION_MOVE -> handleActionMove(event)

MotionEvent.ACTION_UP -> reset()
MotionEvent.ACTION_UP -> onFinish()

MotionEvent.ACTION_CANCEL -> reset()

Expand All @@ -126,39 +145,70 @@ class PatternLockView : GridLayout {
}
}

for(i in 0..(selectedCells.size - 1)) {
var center = selectedCells[i].getCenter()
}

lastX = event.x
lastY = event.y

invalidate()
}

private fun notifyCellSelected(cell: Cell) {
cell.setState(State.SELECTED)
selectedCells.add(cell)

var point = cell.getCenter()
onPatternListener?.onProgress(generateSelectedIds())
if (isSecureMode) return
cell.setState(State.SELECTED)
var center = cell.getCenter()
if (selectedCells.size == 1) {
linePath.moveTo(point.x.toFloat(), point.y.toFloat())
logg("moveTo")
if (lineStyle == LINE_STYLE_COMMON) {
linePath.moveTo(center.x.toFloat(), center.y.toFloat())
}
} else {
linePath.lineTo(point.x.toFloat(), point.y.toFloat())
logg("lineTo")
if (lineStyle == LINE_STYLE_COMMON) {
linePath.lineTo(center.x.toFloat(), center.y.toFloat())
} else if (lineStyle == LINE_STYLE_INDICATOR) {
var previousCell = selectedCells[selectedCells.size - 2]
var previousCellCenter = previousCell.getCenter()
var diffX = center.x - previousCellCenter.x
var diffY = center.y - previousCellCenter.y
var radius = cell.getRadius()
var length = Math.sqrt((diffX * diffX + diffY * diffY).toDouble())

linePath.moveTo((previousCellCenter.x + radius * diffX / length).toFloat(), (previousCellCenter.y + radius * diffY / length).toFloat())
linePath.lineTo((center.x - radius * diffX / length).toFloat(), (center.y - radius * diffY / length).toFloat())

val degree = Math.toDegrees(Math.atan2(diffY.toDouble(), diffX.toDouble())) + 90
previousCell.setDegree(degree.toFloat())
previousCell.invalidate()
}
}
}

override fun dispatchDraw(canvas: Canvas?) {
super.dispatchDraw(canvas)
logg("dispatch")
if (isSecureMode) return
canvas?.drawPath(linePath, linePaint)

if (selectedCells.size > 0 && lastX > 0 && lastY > 0) {
var center = selectedCells[selectedCells.size - 1].getCenter()
canvas?.drawLine(center.x.toFloat(), center.y.toFloat(), lastX, lastY, linePaint)
if (lineStyle == LINE_STYLE_COMMON) {
var center = selectedCells[selectedCells.size - 1].getCenter()
canvas?.drawLine(center.x.toFloat(), center.y.toFloat(), lastX, lastY, linePaint)
} else if (lineStyle == LINE_STYLE_INDICATOR) {
var lastCell = selectedCells[selectedCells.size - 1]
var lastCellCenter = lastCell.getCenter()
var radius = lastCell.getRadius()

if (!(lastX >= lastCellCenter.x - radius &&
lastX <= lastCellCenter.x + radius &&
lastY >= lastCellCenter.y - radius &&
lastY <= lastCellCenter.y + radius)) {
var diffX = lastX - lastCellCenter.x
var diffY = lastY - lastCellCenter.y
var length = Math.sqrt((diffX * diffX + diffY * diffY).toDouble())
canvas?.drawLine((lastCellCenter.x + radius * diffX / length).toFloat(),
(lastCellCenter.y + radius * diffY / length).toFloat(),
lastX, lastY, linePaint)
}
}
}

}

private fun setupCells() {
Expand All @@ -168,7 +218,7 @@ class PatternLockView : GridLayout {
regularCellBackground, regularDotColor, regularDotRadiusRatio,
selectedCellBackground, selectedDotColor, selectedDotRadiusRatio,
errorCellBackground, errorDotColor, errorDotRadiusRatio,
lineStyle, regularLineColor, errorLineColor, plvColumnCount)
lineStyle, regularLineColor, errorLineColor, plvColumnCount, indicatorSizeRatio)
var cellPadding = spacing / 2
cell.setPadding(cellPadding, cellPadding, cellPadding, cellPadding)
addView(cell)
Expand All @@ -190,35 +240,78 @@ class PatternLockView : GridLayout {
}

private fun reset() {
logg(selectedCells.size.toString())
for(cell in selectedCells) {
cell.setState(State.REGULAR)
cell.reset()
}
selectedCells.clear()
linePaint.color = regularLineColor
linePath.reset()

lastX = 0f
lastY = 0f

invalidate()
}

fun enableSecureMode(enabled: Boolean) {
isSecureMode = enabled
}

private fun getHitCell(x: Int, y: Int) : Cell? {
for(cell in cells) {
if (isPointInsideView(cell, x, y)) {
if (isSelected(cell, x, y)) {
return cell
}
}
return null
}

private fun isPointInsideView(view: View, x: Int, y: Int) : Boolean {
var insidePadding = view.width * 0.2
return x >= view.left + insidePadding &&
x <= view.right - insidePadding &&
y >= view.top + insidePadding &&
y <= view.bottom - insidePadding
private fun isSelected(view: View, x: Int, y: Int) : Boolean {
var innerPadding = view.width * hitAreaPaddingRatio
return x >= view.left + innerPadding &&
x <= view.right - innerPadding &&
y >= view.top + innerPadding &&
y <= view.bottom - innerPadding
}

private fun onFinish() {
var error = onPatternListener?.onComplete(generateSelectedIds())
if (error != null && error) {
onError()
} else {
reset()
}
}

private fun generateSelectedIds() : ArrayList<Int> {
var result = ArrayList<Int>()
for(cell in selectedCells) {
result.add(cell.index)
}
return result
}

private fun onError() {
if (isSecureMode) return
for (cell in selectedCells) {
cell.setState(State.ERROR)
}
linePaint.color = errorLineColor
invalidate()

postDelayed({
reset()
}, errorDuration.toLong())

}

fun setOnPatternListener(listener: OnPatternListener) {
onPatternListener = listener
}

fun logg(log: String) {
Log.d("plv_", log)
interface OnPatternListener {
fun onStarted(){}
fun onProgress(ids: ArrayList<Int>){}
fun onComplete(ids: ArrayList<Int>) : Boolean
}
}
4 changes: 4 additions & 0 deletions library/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@

<attr name="plv_rowCount" format="integer"/>
<attr name="plv_columnCount" format="integer"/>

<attr name="plv_errorDuration" format="integer"/>
<attr name="plv_hitAreaPaddingRatio" format="float"/>
<attr name="plv_indicatorSizeRatio" format="float"/>
</declare-styleable>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.itsxtt.patternlock

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.GridLayout

class MainActivity : AppCompatActivity() {

Expand Down
Loading

0 comments on commit 24a7ff9

Please sign in to comment.