diff --git a/MaskedEditText/build.gradle b/MaskedEditText/build.gradle index 2d0dd4e..116f5ad 100644 --- a/MaskedEditText/build.gradle +++ b/MaskedEditText/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' ext { bintrayRepo = 'maven' @@ -43,13 +45,18 @@ android { ext { androidx_appcompat = "1.1.0" + androidx_core_ktx = "1.1.0" } dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - testImplementation 'junit:junit:4.12' api "androidx.appcompat:appcompat:$androidx_appcompat" + implementation "androidx.core:core-ktx:$androidx_core_ktx" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' +repositories { + mavenCentral() +} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/IFormattedString.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/IFormattedString.java deleted file mode 100644 index 39fdd30..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/IFormattedString.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.vicmikhailau.maskededittext; - - -public interface IFormattedString extends CharSequence { - String getUnMaskedString(); -} - - -abstract class AbstractFormattedString implements IFormattedString{ - private String mFormattedString; - private final String mRawString; - private final String mUnmaskedString; - final Mask mMask; - - - AbstractFormattedString(Mask mask, String rawString){ - mMask = mask; - mRawString = rawString; - mUnmaskedString = buildRawString(rawString); - } - - - abstract String formatString(); - abstract String buildRawString(String str); - - public String getUnMaskedString() { - return mUnmaskedString; - } - - - @Override - public int length() { - return toString().length(); - } - - @Override - public String toString() { - if (mFormattedString == null){ - mFormattedString = formatString(); - } - return mFormattedString; - } - - public String getInputString() { - return mRawString; - } - - @Override - public CharSequence subSequence(int start, int end) { - return toString().subSequence(start, end); - } - - @Override - public char charAt(int index) { - return toString().charAt(index); - } -} - -class FormattedString extends AbstractFormattedString { - - FormattedString(Mask mask, String rawString) { - super(mask, rawString); - } - - String buildRawString(String str) { - StringBuilder builder = new StringBuilder(); - int inputLen = Math.min(mMask.size(), str.length()); - for (int i = 0; i < inputLen; i++){ - char ch = str.charAt(i); - if (!mMask.isValidPrepopulateCharacter(ch, i)) - builder.append(ch); - } - return builder.toString(); - } - - String formatString() { - StringBuilder builder = new StringBuilder(); - - int strIndex = 0; - int maskCharIndex = 0; - char stringCharacter; - - while (strIndex < getInputString().length() && maskCharIndex < mMask.size()) { - MaskCharacter maskChar = mMask.get(maskCharIndex); - - stringCharacter = getInputString().charAt(strIndex); - - if (maskChar.isValidCharacter(stringCharacter)) { - builder.append(maskChar.processCharacter(stringCharacter)); - strIndex += 1; - maskCharIndex += 1; - } else if (maskChar.isPrepopulate()) { - builder.append(maskChar.processCharacter(stringCharacter)); - maskCharIndex += 1; - } else { - strIndex += 1; - } - } - - return builder.toString(); - } - - - -} \ No newline at end of file diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/IFormattedString.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/IFormattedString.kt new file mode 100644 index 0000000..df667d1 --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/IFormattedString.kt @@ -0,0 +1,84 @@ +package com.vicmikhailau.maskededittext + + +interface IFormattedString : CharSequence { + val unMaskedString: String +} + + +internal abstract class AbstractFormattedString(val mMask: Mask, val inputString: String) : IFormattedString { + private var mFormattedString: String? = null + final override val unMaskedString: String + + + init { + unMaskedString = this.buildRawString(inputString) + } + + + internal abstract fun formatString(): String + + internal abstract fun buildRawString(str: String): String + + + override val length: Int + get() = toString().length + + override fun toString(): String { + if (mFormattedString == null) { + mFormattedString = formatString() + } + return mFormattedString!! + } + + override fun subSequence(startIndex: Int, endIndex: Int): CharSequence { + return toString().subSequence(startIndex, endIndex) + } + + override fun get(index: Int): Char { + return toString()[index] + } +} + +internal class FormattedString(mask: Mask, rawString: String) : AbstractFormattedString(mask, rawString) { + + override fun buildRawString(str: String): String { + val builder = StringBuilder() + val inputLen = mMask.size().coerceAtMost(str.length) + for (i in 0 until inputLen) { + val ch = str[i] + if (!mMask.isValidPrepopulateCharacter(ch, i)) + builder.append(ch) + } + return builder.toString() + } + + override fun formatString(): String { + val builder = StringBuilder() + + var strIndex = 0 + var maskCharIndex = 0 + var stringCharacter: Char + + while (strIndex < inputString.length && maskCharIndex < mMask.size()) { + val maskChar = mMask[maskCharIndex] + + stringCharacter = inputString[strIndex] + + when { + maskChar.isValidCharacter(stringCharacter) -> { + builder.append(maskChar.processCharacter(stringCharacter)) + strIndex += 1 + maskCharIndex += 1 + } + maskChar.isPrepopulate -> { + builder.append(maskChar.processCharacter(stringCharacter)) + maskCharIndex += 1 + } + else -> strIndex += 1 + } + } + + return builder.toString() + } +} \ No newline at end of file diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/Mask.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/Mask.java deleted file mode 100644 index d071fb1..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/Mask.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.vicmikhailau.maskededittext; - -import java.util.ArrayList; -import java.util.List; - - -public class Mask { - private String mRawMaskString; - private List mMask; - private MaskCharacterFabric mFabric; - private List mPrepopulateCharacter; - - public Mask() { - mFabric = new MaskCharacterFabric(); - } - - public Mask(String fmtString) { - this(); - mRawMaskString = fmtString; - mMask = buildMask(mRawMaskString); - } - - public String getFormatString() { - return mRawMaskString; - } - - public int size() { - return mMask.size(); - } - - public MaskCharacter get(int index) { - return mMask.get(index); - } - - - public boolean isValidPrepopulateCharacter(char ch, int at) { - try { - MaskCharacter character = mMask.get(at); - return character.isPrepopulate() && character.isValidCharacter(ch); - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - public boolean isValidPrepopulateCharacter(char ch){ - for (MaskCharacter maskCharacter : mPrepopulateCharacter){ - if (maskCharacter.isValidCharacter(ch)) { - return true; - } - } - return false; - } - - - private List buildMask(String fmtString) { - List result = new ArrayList<>(); - mPrepopulateCharacter = new ArrayList<>(); - for (char ch : fmtString.toCharArray()) { - MaskCharacter maskCharacter = mFabric.buildCharacter(ch); - if (maskCharacter.isPrepopulate()) { - mPrepopulateCharacter.add(maskCharacter); - } - result.add(maskCharacter); - } - return result; - } - - - public IFormattedString getFormattedString(String value) { - return new FormattedString(this, value); - } - - - -} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/Mask.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/Mask.kt new file mode 100644 index 0000000..cd665cd --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/Mask.kt @@ -0,0 +1,65 @@ +package com.vicmikhailau.maskededittext + +import java.util.* + + +class Mask() { + lateinit var formatString: String + private lateinit var mMask: List + private val mFabric: MaskCharacterFabric = MaskCharacterFabric() + private var mPrepopulateCharacter: MutableList? = null + + constructor(fmtString: String) : this() { + formatString = fmtString + mMask = buildMask(formatString) + } + + fun size(): Int { + return mMask.size + } + + operator fun get(index: Int): MaskCharacter { + return mMask[index] + } + + + fun isValidPrepopulateCharacter(ch: Char, at: Int): Boolean { + return try { + val character = mMask[at] + character.isPrepopulate && character.isValidCharacter(ch) + } catch (e: IndexOutOfBoundsException) { + false + } + + } + + fun isValidPrepopulateCharacter(ch: Char): Boolean { + for (maskCharacter in mPrepopulateCharacter!!) { + if (maskCharacter.isValidCharacter(ch)) { + return true + } + } + return false + } + + + private fun buildMask(fmtString: String): List { + val result = ArrayList() + mPrepopulateCharacter = ArrayList() + for (ch in fmtString.toCharArray()) { + val maskCharacter = mFabric.buildCharacter(ch) + if (maskCharacter?.isPrepopulate == true) { + mPrepopulateCharacter!!.add(maskCharacter) + } + result.add(maskCharacter!!) + } + return result + } + + + fun getFormattedString(value: String): IFormattedString { + return FormattedString(this, value) + } + + +} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacter.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacter.java deleted file mode 100644 index 4366f72..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacter.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.vicmikhailau.maskededittext; - - -abstract class MaskCharacter { - abstract public boolean isValidCharacter(char ch); - - public char processCharacter(char ch) { - return ch; - } - - public boolean isPrepopulate() { - return false; - } - -} - -class DigitCharacter extends MaskCharacter { - @Override - public boolean isValidCharacter(char ch) { - return Character.isDigit(ch); - } - -} - -class UpperCaseCharacter extends MaskCharacter { - @Override - public boolean isValidCharacter(char ch) { - return Character.isUpperCase(ch); - } - - @Override - public char processCharacter(char ch) { - return Character.toUpperCase(ch); - } -} - - -class LowerCaseCharacter extends MaskCharacter { - @Override - public boolean isValidCharacter(char ch) { - return Character.isLowerCase(ch); - } - - @Override - public char processCharacter(char ch) { - return Character.toLowerCase(ch); - } -} - -class AlphaNumericCharacter extends MaskCharacter { - @Override - public boolean isValidCharacter(char ch) { - return Character.isLetterOrDigit(ch); - } -} - -class LetterCharacter extends MaskCharacter { - @Override - public boolean isValidCharacter(char ch) { - return Character.isLetter(ch); - } -} - -class HexCharacter extends MaskCharacter { - private static final String HEX_CHARS = "0123456789ABCDEF"; - - @Override - public boolean isValidCharacter(char ch) { - return Character.isLetterOrDigit(ch) && HEX_CHARS.indexOf(Character.toUpperCase(ch)) != -1; - } - - @Override - public char processCharacter(char ch) { - return Character.toUpperCase(ch); - } -} - -class LiteralCharacter extends MaskCharacter { - private Character character; - - LiteralCharacter() { - character = null; - } - - LiteralCharacter(char ch) { - character = ch; - } - - @Override - public boolean isValidCharacter(char ch) { - return character == null || character == ch; - } - - - @Override - public char processCharacter(char ch) { - if (character != null) - return character; - return ch; - } - - public boolean isPrepopulate() { - return character != null; - } -} - diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacter.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacter.kt new file mode 100644 index 0000000..58353e0 --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacter.kt @@ -0,0 +1,95 @@ +package com.vicmikhailau.maskededittext + + +abstract class MaskCharacter { + + open val isPrepopulate: Boolean + get() = false + + abstract fun isValidCharacter(ch: Char): Boolean + + open fun processCharacter(ch: Char): Char { + return ch + } + +} + +internal class DigitCharacter : MaskCharacter() { + override fun isValidCharacter(ch: Char): Boolean { + return Character.isDigit(ch) + } + +} + +internal class UpperCaseCharacter : MaskCharacter() { + override fun isValidCharacter(ch: Char): Boolean { + return Character.isUpperCase(ch) + } + + override fun processCharacter(ch: Char): Char { + return Character.toUpperCase(ch) + } +} + + +internal class LowerCaseCharacter : MaskCharacter() { + override fun isValidCharacter(ch: Char): Boolean { + return Character.isLowerCase(ch) + } + + override fun processCharacter(ch: Char): Char { + return Character.toLowerCase(ch) + } +} + +internal class AlphaNumericCharacter : MaskCharacter() { + override fun isValidCharacter(ch: Char): Boolean { + return Character.isLetterOrDigit(ch) + } +} + +internal class LetterCharacter : MaskCharacter() { + override fun isValidCharacter(ch: Char): Boolean { + return Character.isLetter(ch) + } +} + +internal class HexCharacter : MaskCharacter() { + + override fun isValidCharacter(ch: Char): Boolean { + return Character.isLetterOrDigit(ch) && HEX_CHARS.indexOf(Character.toUpperCase(ch)) != -1 + } + + override fun processCharacter(ch: Char): Char { + return Character.toUpperCase(ch) + } + + companion object { + private val HEX_CHARS = "0123456789ABCDEF" + } +} + +internal class LiteralCharacter : MaskCharacter { + private var character: Char? = null + + override val isPrepopulate: Boolean + get() = character != null + + constructor() { + character = null + } + + constructor(ch: Char) { + character = ch + } + + override fun isValidCharacter(ch: Char): Boolean { + return character == null || character == ch + } + + + override fun processCharacter(ch: Char): Char { + return if (character != null) character!! else ch + } +} + diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacterFabric.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacterFabric.java deleted file mode 100644 index 5bafbef..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacterFabric.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.vicmikhailau.maskededittext; - - -class MaskCharacterFabric { - private static final char ANYTHING_KEY = '*'; - private static final char DIGIT_KEY = '#'; - private static final char UPPERCASE_KEY = 'U'; - private static final char LOWERCASE_KEY = 'L'; - private static final char ALPHA_NUMERIC_KEY = 'A'; - private static final char CHARACTER_KEY = '?'; - private static final char HEX_KEY = 'H'; - - MaskCharacter buildCharacter(char ch) { - MaskCharacter result = null; - switch (ch) { - case ANYTHING_KEY: - result = new LiteralCharacter(); - break; - case DIGIT_KEY: - result = new DigitCharacter(); - break; - case UPPERCASE_KEY: - result = new UpperCaseCharacter(); - break; - case LOWERCASE_KEY: - result = new LowerCaseCharacter(); - break; - case ALPHA_NUMERIC_KEY: - result = new AlphaNumericCharacter(); - break; - case CHARACTER_KEY: - result = new LetterCharacter(); - break; - case HEX_KEY: - result = new HexCharacter(); - break; - default: { - result = new LiteralCharacter(ch); - } - - } - return result; - } -} - diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacterFabric.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacterFabric.kt new file mode 100644 index 0000000..dd2fbe6 --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskCharacterFabric.kt @@ -0,0 +1,31 @@ +package com.vicmikhailau.maskededittext + + +internal class MaskCharacterFabric { + + fun buildCharacter(ch: Char): MaskCharacter? { + return when (ch) { + ANYTHING_KEY -> LiteralCharacter() + DIGIT_KEY -> DigitCharacter() + UPPERCASE_KEY -> UpperCaseCharacter() + LOWERCASE_KEY -> LowerCaseCharacter() + ALPHA_NUMERIC_KEY -> AlphaNumericCharacter() + CHARACTER_KEY -> LetterCharacter() + HEX_KEY -> HexCharacter() + else -> { + LiteralCharacter(ch) + } + } + } + + companion object { + private const val ANYTHING_KEY = '*' + private const val DIGIT_KEY = '#' + private const val UPPERCASE_KEY = 'U' + private const val LOWERCASE_KEY = 'L' + private const val ALPHA_NUMERIC_KEY = 'A' + private const val CHARACTER_KEY = '?' + private const val HEX_KEY = 'H' + } +} + diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedEditText.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedEditText.java deleted file mode 100644 index 8c417f6..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedEditText.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.vicmikhailau.maskededittext; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; - -import androidx.appcompat.widget.AppCompatEditText; - -public class MaskedEditText extends AppCompatEditText { - - // =========================================================== - // Fields - // =========================================================== - - private MaskedFormatter mMaskedFormatter; - private MaskedWatcher mMaskedWatcher; - - // =========================================================== - // Constructors - // =========================================================== - - public MaskedEditText(Context context, AttributeSet attrs) { - super(context, attrs); - - TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaskedEditText); - - if (typedArray.hasValue(R.styleable.MaskedEditText_mask)) { - String maskStr = typedArray.getString(R.styleable.MaskedEditText_mask); - - if (maskStr != null && !maskStr.isEmpty()) { - setMask(maskStr); - } - } - - typedArray.recycle(); - } - - // =========================================================== - // Getter & Setter - // =========================================================== - - public String getMaskString() { - return mMaskedFormatter.getMaskString(); - } - - public String getUnMaskedText() { - String currentText = getText().toString(); - IFormattedString formattedString = mMaskedFormatter.formatString(currentText); - return formattedString.getUnMaskedString(); - } - - public void setMask(String mMaskStr) { - mMaskedFormatter = new MaskedFormatter(mMaskStr); - - if (mMaskedWatcher != null) { - removeTextChangedListener(mMaskedWatcher); - } - - mMaskedWatcher = new MaskedWatcher(mMaskedFormatter, this); - addTextChangedListener(mMaskedWatcher); - } - -} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedEditText.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedEditText.kt new file mode 100644 index 0000000..841fd86 --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedEditText.kt @@ -0,0 +1,60 @@ +package com.vicmikhailau.maskededittext + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatEditText + +class MaskedEditText(context: Context, attrs: AttributeSet) : AppCompatEditText(context, attrs) { + + // =========================================================== + // Constructors + // =========================================================== + + // =========================================================== + // Fields + // =========================================================== + + private var mMaskedFormatter: MaskedFormatter? = null + private var mMaskedWatcher: MaskedWatcher? = null + + // =========================================================== + // Getter & Setter + // =========================================================== + + val maskString: String? + get() = mMaskedFormatter!!.maskString + + val unMaskedText: String + get() { + val currentText = text!!.toString() + val formattedString = mMaskedFormatter!!.formatString(currentText) + return formattedString.unMaskedString + } + + init { + + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaskedEditText) + + if (typedArray.hasValue(R.styleable.MaskedEditText_mask)) { + val maskStr = typedArray.getString(R.styleable.MaskedEditText_mask) + + if (maskStr != null && maskStr.isNotEmpty()) { + setMask(maskStr) + } + } + + typedArray.recycle() + } + + fun setMask(mMaskStr: String) { + mMaskedFormatter = MaskedFormatter(mMaskStr) + + if (mMaskedWatcher != null) { + removeTextChangedListener(mMaskedWatcher) + } + + mMaskedWatcher = MaskedWatcher(mMaskedFormatter!!, this) + addTextChangedListener(mMaskedWatcher) + } + +} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedFormatter.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedFormatter.java deleted file mode 100644 index 26f4b24..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedFormatter.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.vicmikhailau.maskededittext; - - -public class MaskedFormatter { - Mask mMask; - - MaskedFormatter() { - mMask = null; - } - - public MaskedFormatter(String fmtString) { - this(); - this.setMask(fmtString); - } - - - public String getMaskString() { - if (mMask != null) { - return mMask.getFormatString(); - } - return null; - } - - public int getMaskLength() { - return mMask.size(); - } - - public void setMask(String fmtString) { - mMask = new Mask(fmtString); - } - - - public IFormattedString formatString(String value) { - return mMask.getFormattedString(value); - } - -} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedFormatter.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedFormatter.kt new file mode 100644 index 0000000..6a508c8 --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedFormatter.kt @@ -0,0 +1,33 @@ +package com.vicmikhailau.maskededittext + + +class MaskedFormatter internal constructor() { + internal var mMask: Mask? = null + + + val maskString: String? + get() = if (mMask != null) { + mMask!!.formatString + } else null + + val maskLength: Int + get() = mMask!!.size() + + init { + mMask = null + } + + constructor(fmtString: String) : this() { + this.setMask(fmtString) + } + + fun setMask(fmtString: String) { + mMask = Mask(fmtString) + } + + + fun formatString(value: String): IFormattedString { + return mMask!!.getFormattedString(value) + } + +} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedWatcher.java b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedWatcher.java deleted file mode 100644 index 2f0dbbe..0000000 --- a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedWatcher.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.vicmikhailau.maskededittext; - -import android.text.Editable; -import android.text.TextWatcher; -import android.widget.EditText; - -import java.lang.ref.WeakReference; - -public class MaskedWatcher implements TextWatcher { - // =========================================================== - // Fields - // =========================================================== - - private final WeakReference mMaskFormatter; - private final WeakReference mEditText; - private String oldFormattedValue = ""; - private int oldCursorPosition; - - // =========================================================== - // Constructors - // =========================================================== - - public MaskedWatcher(MaskedFormatter maskedFormatter, EditText editText) { - mMaskFormatter = new WeakReference<>(maskedFormatter); - mEditText = new WeakReference<>(editText); - } - - // =========================================================== - // Listeners, methods for/from Interfaces - // =========================================================== - - private void setFormattedText(IFormattedString formattedString) { - EditText editText = mEditText.get(); - if (editText == null) { - return; - } - - int deltaLength = formattedString.length() - oldFormattedValue.length(); - - - editText.removeTextChangedListener(this); - editText.setText(formattedString); - editText.addTextChangedListener(this); - - int newCursorPosition = oldCursorPosition; - - if (deltaLength > 0) { - newCursorPosition += deltaLength; - } else if (deltaLength < 0) { - newCursorPosition -= 1; - } else { - Mask mask = mMaskFormatter.get().mMask; - newCursorPosition = Math.max(1, Math.min(newCursorPosition, mMaskFormatter.get().getMaskLength())); - if (mask.get(newCursorPosition - 1).isPrepopulate()) - newCursorPosition -= 1; - } - newCursorPosition = Math.max(0, Math.min(newCursorPosition, formattedString.length())); - editText.setSelection(newCursorPosition); - } - - @Override - public void afterTextChanged(Editable s) { - if (s == null) - return; - - String value = s.toString(); - - if (value.length() > oldFormattedValue.length() && mMaskFormatter.get().getMaskLength() < value.length()) { - value = oldFormattedValue; - } - - IFormattedString formattedString = mMaskFormatter.get().formatString(value); - - setFormattedText(formattedString); - oldFormattedValue = formattedString.toString(); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - this.oldCursorPosition = mEditText.get().getSelectionStart(); - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } -} diff --git a/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedWatcher.kt b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedWatcher.kt new file mode 100644 index 0000000..53a6533 --- /dev/null +++ b/MaskedEditText/src/main/java/com/vicmikhailau/maskededittext/MaskedWatcher.kt @@ -0,0 +1,75 @@ +package com.vicmikhailau.maskededittext + +import android.text.Editable +import android.text.TextWatcher +import android.widget.EditText + +import java.lang.ref.WeakReference + +class MaskedWatcher(maskedFormatter: MaskedFormatter, editText: EditText) : TextWatcher { + + // =========================================================== + // Constructors + // =========================================================== + + // =========================================================== + // Fields + // =========================================================== + + private val mMaskFormatter: WeakReference = WeakReference(maskedFormatter) + private val mEditText: WeakReference = WeakReference(editText) + private var oldFormattedValue = "" + private var oldCursorPosition: Int = 0 + + // =========================================================== + // Listeners, methods for/from Interfaces + // =========================================================== + + private fun setFormattedText(formattedString: IFormattedString) { + val editText = mEditText.get() ?: return + + val deltaLength = formattedString.length - oldFormattedValue.length + + + editText.removeTextChangedListener(this) + editText.setText(formattedString) + editText.addTextChangedListener(this) + + var newCursorPosition = oldCursorPosition + + if (deltaLength > 0) { + newCursorPosition += deltaLength + } else if (deltaLength < 0) { + newCursorPosition -= 1 + } else { + val mask = mMaskFormatter.get()!!.mMask + newCursorPosition = 1.coerceAtLeast(newCursorPosition.coerceAtMost(mMaskFormatter.get()!!.maskLength)) + if (mask!![newCursorPosition - 1].isPrepopulate) + newCursorPosition -= 1 + } + newCursorPosition = 0.coerceAtLeast(newCursorPosition.coerceAtMost(formattedString.length)) + editText.setSelection(newCursorPosition) + } + + override fun afterTextChanged(s: Editable?) { + if (s == null) + return + + var value = s.toString() + + if (value.length > oldFormattedValue.length && mMaskFormatter.get()!!.maskLength < value.length) { + value = oldFormattedValue + } + + val formattedString = mMaskFormatter.get()!!.formatString(value) + + setFormattedText(formattedString) + oldFormattedValue = formattedString.toString() + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + this.oldCursorPosition = mEditText.get()!!.selectionStart + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} +} diff --git a/app/build.gradle b/app/build.gradle index d5cfe4d..64a9087 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' android { compileSdkVersion 29 @@ -20,6 +22,7 @@ android { ext { androidx_appcompat = "1.1.0" + androidx_core_ktx = "1.1.0" } dependencies { @@ -27,4 +30,9 @@ dependencies { testImplementation 'junit:junit:4.12' implementation "androidx.appcompat:appcompat:$androidx_appcompat" implementation project(':MaskedEditText') + implementation "androidx.core:core-ktx:$androidx_core_ktx" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} +repositories { + mavenCentral() } diff --git a/app/src/main/java/com/vicmikhailau/maskededittextsample/MainActivity.java b/app/src/main/java/com/vicmikhailau/maskededittextsample/MainActivity.kt similarity index 62% rename from app/src/main/java/com/vicmikhailau/maskededittextsample/MainActivity.java rename to app/src/main/java/com/vicmikhailau/maskededittextsample/MainActivity.kt index acbc030..017042e 100644 --- a/app/src/main/java/com/vicmikhailau/maskededittextsample/MainActivity.java +++ b/app/src/main/java/com/vicmikhailau/maskededittextsample/MainActivity.kt @@ -1,15 +1,12 @@ -package com.vicmikhailau.maskededittextsample; +package com.vicmikhailau.maskededittextsample -import android.os.Bundle; -import android.widget.EditText; +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.vicmikhailau.maskededittext.MaskedFormatter +import com.vicmikhailau.maskededittext.MaskedWatcher +import kotlinx.android.synthetic.main.activity_main.* -import com.vicmikhailau.maskededittext.MaskedEditText; -import com.vicmikhailau.maskededittext.MaskedFormatter; -import com.vicmikhailau.maskededittext.MaskedWatcher; - -import androidx.appcompat.app.AppCompatActivity; - -public class MainActivity extends AppCompatActivity { +class MainActivity : AppCompatActivity() { /** * Use specific values for create your own mask (see example below or in xml): @@ -36,9 +33,7 @@ public class MainActivity extends AppCompatActivity { // Fields // =========================================================== - private MaskedEditText mEdtMaskedCustom; - private EditText mEdtMasked; - private MaskedFormatter formatter; + private var formatter: MaskedFormatter? = null // =========================================================== // Constructors @@ -53,12 +48,10 @@ public class MainActivity extends AppCompatActivity { // =========================================================== - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - findViews(); - setMask("##/##/####"); + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + setMask("##/##/####") } // =========================================================== @@ -69,11 +62,6 @@ protected void onCreate(Bundle savedInstanceState) { // Methods // =========================================================== - private void findViews() { - mEdtMaskedCustom = (MaskedEditText) findViewById(R.id.edt_masked_custom); - mEdtMasked = (EditText) findViewById(R.id.edt_masked); - } - /** * You cas use MaskedEditText declared in xml with attribute named mask * or @@ -81,14 +69,14 @@ private void findViews() { * * @param mask your mask */ - private void setMask(String mask) { - formatter = new MaskedFormatter(mask); - mEdtMasked.addTextChangedListener(new MaskedWatcher(formatter, mEdtMasked)); - String s = formatter.formatString(mEdtMasked.getText().toString()).getUnMaskedString(); + private fun setMask(mask: String) { + formatter = MaskedFormatter(mask) + edtMasked.addTextChangedListener(MaskedWatcher(formatter!!, edtMasked!!)) + val s = formatter?.formatString(edtMasked.text.toString())?.unMaskedString } - private void getUnMaskedTextForEdtCustom() { - mEdtMaskedCustom.getUnMaskedText(); + private fun getUnMaskedTextForEdtCustom() { + edtMaskedCustom.unMaskedText } // =========================================================== diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ada1cab..ba4a1a9 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,7 +13,7 @@ MaskedEditTextSample 12.12.12 (029)777-77-77 - 12/12/2016 + 12/12/2019 diff --git a/build.gradle b/build.gradle index 580df11..5e44413 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.50' repositories { jcenter() google() @@ -9,6 +10,7 @@ buildscript { classpath 'com.android.tools.build:gradle:3.5.2' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -17,8 +19,4 @@ allprojects { jcenter() google() } -} - -task clean(type: Delete) { - delete rootProject.buildDirt -} +} \ No newline at end of file