Pages

Tuesday, 9 January 2018

SuperNova Emoji Library is now available in Kotlin for Android




Download Kotlin Source from Github: Download

Platform: Android 4.1 +

Language: Kotlin

Package AAR: Download

Maven:


Build Via Gradle: implementation 'com.dbh4ck:supernova-emoji-kotlin:1.0'

Origin: supernova emoji for android

Monday, 8 January 2018

Thursday, 4 January 2018

AutoFillSmsOTP in Kotlin with Custom Editables for Android




package com.db.smsotpautofillkotlin.editable
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.support.annotation.ColorInt
import android.support.v4.content.ContextCompat
import android.text.*
import android.util.AttributeSet
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputMethodManager
import com.db.smsotpautofillkotlin.R
import com.db.smsotpautofillkotlin.interfaces.EditCodeListener
import android.text.Editable
import com.db.smsotpautofillkotlin.interfaces.EditCodeWatcher
/**
* Created by DB on 04-01-2018.
*/
class EditCodeView: View, View.OnClickListener, View.OnFocusChangeListener {
private val textWatcher = CodeTextWatcher()
private var inputmethodmanager: InputMethodManager? = null
private var editCodeInputConnection: EditCodeInputConnection? = null
private var editCodeListener: EditCodeListener? = null
private var editCodeWatcher: EditCodeWatcher? = null
private var editable: Editable? = null
private var textPaint: Paint? = null
private var underlinePaint: Paint? = null
private var cursorPaint: Paint? = null
private var textSize: Float = 0.toFloat()
private var textPosY: Float = 0.toFloat()
private var textColor: Int = 0
private var sectionWidth: Float = 0.toFloat()
private var codeLength: Int = 0
private var symbolWidth: Float = 0.toFloat()
private var symbolMaskedWidth: Float = 0.toFloat()
private var underlineHorizontalPadding: Float = 0.toFloat()
private var underlineReductionScale: Float = 0.toFloat()
private var underlineStrokeWidth: Float = 0.toFloat()
private var underlineBaseColor: Int = 0
private var underlineSelectedColor: Int = 0
private var underlineFilledColor: Int = 0
private var underlineCursorColor: Int = 0
private var underlinePosY: Float = 0.toFloat()
private var fontStyle: Int = 0
private var cursorEnabled: Boolean = false
private var codeHiddenMode: Boolean = false
private var _isSelected: Boolean = false
private var codeHiddenMask: String? = null
private val textBounds = Rect()
constructor(context: Context): this(context, null){
}
constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0){
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr){
init(context, attrs)
}
private val cursorAnimation = object : Runnable {
override fun run() {
val color = if (cursorPaint!!.getColor() === underlineSelectedColor)
underlineCursorColor
else
underlineSelectedColor
cursorPaint!!.setColor(color)
invalidate()
postDelayed(this, 500)
}
}
private fun init(context: Context, attrs: AttributeSet?) {
initDefaultAttrs(context)
initCustomAttrs(context, attrs)
initPaints()
initViewsOptions(context)
if (isInEditMode) {
editModePreview()
}
}
private fun initDefaultAttrs(context: Context) {
val resources = context.resources
underlineReductionScale = DEFAULT_REDUCTION_SCALE!!
underlineStrokeWidth = resources.getDimension(R.dimen.underline_stroke_width)
underlineBaseColor = ContextCompat.getColor(context, R.color.underline_base_color)
underlineFilledColor = ContextCompat.getColor(context, R.color.underline_filled_color)
underlineCursorColor = ContextCompat.getColor(context, R.color.underline_cursor_color)
underlineSelectedColor = ContextCompat.getColor(context, R.color.underline_selected_color)
textSize = resources.getDimension(R.dimen.code_text_size)
textColor = ContextCompat.getColor(context, R.color.text_main_color)
codeLength = DEFAULT_CODE_LENGTH!!
codeHiddenMask = DEFAULT_CODE_MASK
}
private fun initCustomAttrs(context: Context, attributeSet: AttributeSet?) {
if (attributeSet == null) return
val attributes = context.obtainStyledAttributes(
attributeSet, R.styleable.EditCodeView)
underlineStrokeWidth = attributes.getDimension(
R.styleable.EditCodeView_underlineStroke, underlineStrokeWidth)
underlineReductionScale = attributes.getFloat(
R.styleable.EditCodeView_underlineReductionScale, underlineReductionScale)
underlineBaseColor = attributes.getColor(
R.styleable.EditCodeView_underlineBaseColor, underlineBaseColor)
underlineSelectedColor = attributes.getColor(
R.styleable.EditCodeView_underlineSelectedColor, underlineSelectedColor)
underlineFilledColor = attributes.getColor(
R.styleable.EditCodeView_underlineFilledColor, underlineFilledColor)
underlineCursorColor = attributes.getColor(
R.styleable.EditCodeView_underlineCursorColor, underlineCursorColor)
cursorEnabled = attributes.getBoolean(
R.styleable.EditCodeView_underlineCursorEnabled, cursorEnabled)
textSize = attributes.getDimension(
R.styleable.EditCodeView_textSize, textSize)
textColor = attributes.getColor(
R.styleable.EditCodeView_textColor, textColor)
fontStyle = attributes.getInt(
R.styleable.EditCodeView_fontStyle, fontStyle)
codeLength = attributes.getInt(
R.styleable.EditCodeView_codeLength, DEFAULT_CODE_LENGTH!!)
codeHiddenMode = attributes.getBoolean(
R.styleable.EditCodeView_codeHiddenMode, codeHiddenMode)
val mask = attributes.getString(R.styleable.EditCodeView_codeHiddenMask)
if (mask != null && mask.length > 0) {
codeHiddenMask = mask.substring(0, 1)
}
attributes.recycle()
}
private fun editModePreview() {
for (i in 0 until codeLength) {
if (codeHiddenMode) {
editable!!.append(codeHiddenMask)
} else {
editable!!.append(DEFAULT_CODE_SYMBOL)
}
}
}
@SuppressLint("WrongConstant")
private fun initPaints() {
textPaint = Paint()
textPaint!!.setColor(textColor)
textPaint!!.setTextSize(textSize)
textPaint!!.setTypeface(Typeface.create(Typeface.DEFAULT, fontStyle))
textPaint!!.setAntiAlias(true)
underlinePaint = Paint()
underlinePaint!!.setColor(underlineBaseColor)
underlinePaint!!.setStrokeWidth(underlineStrokeWidth)
cursorPaint = Paint()
cursorPaint!!.setColor(underlineBaseColor)
cursorPaint!!.setStrokeWidth(underlineStrokeWidth)
}
private fun initViewsOptions(context: Context) {
setOnClickListener(this)
isFocusable = true
isFocusableInTouchMode = true
onFocusChangeListener = this
inputmethodmanager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
editable = Editable.Factory.getInstance().newEditable("")
editable!!.setSpan(textWatcher, 0, editable!!.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
Selection.setSelection(editable, 0)
editCodeInputConnection = EditCodeInputConnection(this, true, codeLength)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
measureSizes(w, h)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec))
}
override fun onDraw(canvas: Canvas) {
drawUnderline(canvas)
drawText(canvas)
}
override fun onFocusChange(v: View, hasFocus: Boolean) {
_isSelected = hasFocus
if (hasFocus) {
if (cursorEnabled) {
post(cursorAnimation)
}
showKeyboard()
} else {
if (cursorEnabled) {
removeCallbacks(cursorAnimation)
}
hideKeyboard()
}
}
private fun drawText(canvas: Canvas) {
if (codeHiddenMode) {
val symbol = charArrayOf(codeHiddenMask!!.get(0))
for (i in 0 until editable!!.length) {
val textPosX = sectionWidth * i + sectionWidth / 2 - symbolMaskedWidth / 2
canvas.drawText(symbol, 0, 1, textPosX, textPosY, textPaint)
}
} else {
for (i in 0 until editable!!.length) {
val symbol = charArrayOf(editable!!.get(i))
val textPosX = sectionWidth * i + sectionWidth / 2 - symbolWidth / 2
canvas.drawText(symbol, 0, 1, textPosX, textPosY, textPaint)
}
}
}
private fun drawUnderline(canvas: Canvas) {
for (i in 0 until codeLength) {
val startPosX = sectionWidth * i + underlineHorizontalPadding
val endPosX = startPosX + sectionWidth - underlineHorizontalPadding * 2
if (cursorEnabled && _isSelected && editable!!.length == i) {
canvas.drawLine(startPosX, underlinePosY, endPosX, underlinePosY, cursorPaint)
} else {
if (editable!!.length <= i && _isSelected) {
underlinePaint!!.setColor(underlineSelectedColor)
} else if (editable!!.length <= i && !_isSelected) {
underlinePaint!!.setColor(underlineBaseColor)
} else {
underlinePaint!!.setColor(underlineFilledColor)
}
canvas.drawLine(startPosX, underlinePosY, endPosX, underlinePosY, underlinePaint)
}
}
}
private fun measureSizes(viewWidth: Int, viewHeight: Int) {
if (underlineReductionScale > 1) underlineReductionScale = 1f
if (underlineReductionScale < 0) underlineReductionScale = 0f
if (codeLength <= 0) {
throw IllegalArgumentException("Code length must be over than zero")
}
symbolWidth = textPaint!!.measureText(DEFAULT_CODE_SYMBOL)
symbolMaskedWidth = textPaint!!.measureText(codeHiddenMask)
textPaint!!.getTextBounds(DEFAULT_CODE_SYMBOL, 0, 1, textBounds)
sectionWidth = (viewWidth / codeLength).toFloat()
underlinePosY = (viewHeight - paddingBottom).toFloat()
underlineHorizontalPadding = sectionWidth * underlineReductionScale / 2
textPosY = (viewHeight / 2 + textBounds.height() / 2).toFloat()
}
private fun measureHeight(measureSpec: Int): Int {
val size = (paddingBottom.toFloat()
+ paddingTop.toFloat()
+ textBounds.height().toFloat()
+ textSize
+ underlineStrokeWidth).toInt()
return View.resolveSizeAndState(size, measureSpec, 0)
}
private fun measureWidth(measureSpec: Int): Int {
val size = ((paddingLeft.toFloat() + paddingRight.toFloat() + textSize) * codeLength.toFloat() * 2f).toInt()
return View.resolveSizeAndState(size, measureSpec, 0)
}
fun setEditCodeListener(EditCodeListener: EditCodeListener) {
this.editCodeListener = EditCodeListener
}
fun setCode(code: String) {
var code = code
code = code.replace(DEFAULT_REGEX.toRegex(), "")
editCodeInputConnection!!.setComposingText(code, 1)
editCodeInputConnection!!.finishComposingText()
}
fun clearCode() {
editCodeInputConnection!!.setComposingRegion(0, codeLength)
editCodeInputConnection!!.setComposingText("", 0)
editCodeInputConnection!!.finishComposingText()
}
fun getCode(): String {
return editable.toString()
}
fun setReductionScale(scale: Float) {
var scale = scale
if (scale > 1) scale = 1f
if (scale < 0) scale = 0f
underlineReductionScale = scale
invalidate()
}
fun setCodeHiddenMode(hiddenMode: Boolean) {
codeHiddenMode = hiddenMode
invalidate()
}
fun setUnderlineBaseColor(@ColorInt colorId: Int) {
underlineBaseColor = colorId
invalidate()
}
fun setUnderlineFilledColor(@ColorInt colorId: Int) {
underlineFilledColor = colorId
invalidate()
}
fun setUnderlineSelectedColor(@ColorInt colorId: Int) {
underlineSelectedColor = colorId
invalidate()
}
fun setUnderlineCursorColor(@ColorInt colorId: Int) {
underlineCursorColor = colorId
invalidate()
}
fun setTextColor(@ColorInt colorId: Int) {
textColor = colorId
invalidate()
}
fun setUnderlineStrokeWidth(underlineStrokeWidth: Float) {
this.underlineStrokeWidth = underlineStrokeWidth
invalidate()
}
fun setCodeLength(length: Int) {
codeLength = length
editCodeInputConnection = EditCodeInputConnection(this, true, codeLength)
editable!!.clear()
inputmethodmanager!!.restartInput(this)
invalidate()
}
fun setEditCodeWatcher(editCodeWatcher: EditCodeWatcher) {
this.editCodeWatcher = editCodeWatcher
}
fun getCodeLength(): Int {
return codeLength
}
fun showKeyboard() {
inputmethodmanager!!.showSoftInput(this, 0)
}
fun hideKeyboard() {
inputmethodmanager!!.hideSoftInputFromWindow(
windowToken,
InputMethodManager.RESULT_UNCHANGED_SHOWN)
}
override fun onClick(v: View) {
showKeyboard()
}
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE
outAttrs.initialSelStart = 0
return this.editCodeInputConnection!!
}
override fun setSelected(selected: Boolean) {
_isSelected = selected
invalidate()
}
fun getEditable(): Editable {
return editable!!
}
override fun onCheckIsTextEditor(): Boolean {
return true
}
private inner class CodeTextWatcher : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
invalidate()
if (editCodeWatcher != null) {
editCodeWatcher!!.onCodeChanged(s.toString())
}
if (editable!!.length == codeLength) {
if (editCodeListener != null) {
editCodeListener!!.onCodeReady(editable.toString())
}
}
}
}
companion object {
private val DEFAULT_CODE_LENGTH: Int? = 4
private val DEFAULT_CODE_MASK = "*"
private val DEFAULT_CODE_SYMBOL = "0"
private val DEFAULT_REGEX = "[^0-9]"
private val DEFAULT_REDUCTION_SCALE: Float? = 0.5f
}
}
view raw EditCodeView.kt hosted with ❤ by GitHub

package com.db.smsotpautofillkotlin.editable
import android.view.View
import android.view.inputmethod.BaseInputConnection
import android.text.Editable
import android.view.KeyEvent
/**
* Created by DB on 03-01-2018.
*/
class EditCodeInputConnection(targetView: View, fullEditor: Boolean, textLength: Int): BaseInputConnection(targetView, fullEditor) {
private var _editable: Editable? = null
private var textLength: Int = 0
init {
val view = targetView as EditCodeView
this.textLength = textLength
this._editable = view.getEditable()
}
override fun getEditable(): Editable {
return this._editable!!
}
override fun sendKeyEvent(event: KeyEvent): Boolean {
if (event.getAction() === KeyEvent.ACTION_DOWN) {
if (event.getKeyCode() >= KeyEvent.KEYCODE_0 && event.getKeyCode() <= KeyEvent.KEYCODE_9) {
val c = event.getKeyCharacterMap().getNumber(event.getKeyCode())
commitText(c.toString(), 1)
} else if (event.getKeyCode() === KeyEvent.KEYCODE_DEL) {
deleteSurroundingText(1, 0)
}
}
return super.sendKeyEvent(event)
}
override fun commitText(text: CharSequence, newCursorPosition: Int): Boolean {
return _editable!!.length + text.length <= textLength && super.commitText(text.subSequence(0, 1), newCursorPosition)
}
override fun setComposingText(text: CharSequence, newCursorPosition: Int): Boolean {
var text = text
if (text.length > textLength) {
text = text.subSequence(0, textLength)
}
return super.setComposingText(text, newCursorPosition)
}
override fun setComposingRegion(start: Int, end: Int): Boolean {
return super.setComposingRegion(start, end)
}
override fun finishComposingText(): Boolean {
return super.finishComposingText()
}
}

package com.db.smsotpautofillkotlin.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.support.v4.app.NotificationCompat.getExtras
import android.os.Bundle
import android.R.attr.data
import android.telephony.SmsMessage
import java.util.regex.Pattern
import com.db.smsotpautofillkotlin.interfaces.SmsListener
/**
* Created by DB on 03-01-2018.
*/
class SmsReceiver: BroadcastReceiver() {
@Suppress("DEPRECATION")
override fun onReceive(context: Context?, intent: Intent?) {
val data = intent!!.getExtras()
val pdus = data.get("pdus") as Array<Any>
for (i in 0 until pdus.size) {
val smsMessage = SmsMessage.createFromPdu(pdus[i] as ByteArray)
val sender = smsMessage.getDisplayOriginatingAddress()
//Check the sender to filter messages which we require to read
val pattern = Pattern.compile(OTP_SENDER_REGEX)
val matcher = pattern.matcher(sender)
while (matcher.find()) {
val messageBody: String? = smsMessage.getMessageBody()
//Pass the message text to interface
if (messageBody != null) {
mListener!!.messageReceived(messageBody)
}
}
}
}
companion object {
val OTP_SENDER_REGEX: String? = "[0-9a-zA-Z]"
//interface
private var mListener: SmsListener? = null
fun bindListener(listener: SmsListener) {
mListener = listener
}
}
}
view raw SmsReceiver.kt hosted with ❤ by GitHub

package com.db.smsotpautofillkotlin
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.db.smsotpautofillkotlin.interfaces.EditCodeWatcher
import com.db.smsotpautofillkotlin.interfaces.EditCodeListener
import android.view.WindowManager
import com.db.smsotpautofillkotlin.editable.EditCodeView
import com.db.smsotpautofillkotlin.interfaces.SmsListener
import com.db.smsotpautofillkotlin.receivers.SmsReceiver
import java.util.regex.Pattern
class DBSmsOTPActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dbsms_otp)
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
val editCodeView = findViewById(R.id.dbotp) as EditCodeView
editCodeView.setEditCodeListener(object : EditCodeListener {
override fun onCodeReady(code: String) {
}
})
editCodeView.setEditCodeWatcher(object : EditCodeWatcher {
override fun onCodeChanged(code: String) {
Log.e("CodeWatcher", " changed : " + code)
}
})
editCodeView.requestFocus()
SmsReceiver.Companion.bindListener(object : SmsListener {
override fun messageReceived(messageText: String) {
//From the received text string you may do string operations to get the required OTP
//It depends on your SMS format
Log.e("Message", messageText)
// Toast.makeText(DbSmsOTPActivity.this,"Message: " + messageText, Toast.LENGTH_LONG).show();
// If your OTP is six digits number, you may use the below code
val pattern = Pattern.compile(OTP_REGEX)
val matcher = pattern.matcher(messageText)
var otp: String? = null
while (matcher.find()) {
otp = matcher.group()
}
// Toast.makeText(DbSmsOTPActivity.this, "OTP: " + otp , Toast.LENGTH_LONG).show();
assert(otp != null)
editCodeView.setCode(otp!!)
}
})
}
companion object {
val OTP_REGEX: String? = "[0-9]{1,6}"
}
}

package com.db.smsotpautofillkotlin.interfaces
/**
* Created by DB on 03-01-2018.
*/
interface EditCodeListener {
fun onCodeReady(code: String)
}

package com.db.smsotpautofillkotlin.interfaces
/**
* Created by DB on 03-01-2018.
*/
interface EditCodeWatcher {
fun onCodeChanged(code: String)
}

package com.db.smsotpautofillkotlin.interfaces
/**
* Created by DB on 03-01-2018.
*/
interface SmsListener {
fun messageReceived(messageText: String)
}
view raw SmsListener.kt hosted with ❤ by GitHub

Github Source: Download Source