diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
new file mode 100644
index 0000000..e519f16
--- /dev/null
+++ b/.github/workflows/android.yml
@@ -0,0 +1,26 @@
+name: Android CI
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: set up JDK 11
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ cache: gradle
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build with Gradle
+ run: ./gradlew build
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c960a15..263b2d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,31 +1,73 @@
# Changelog
-### `6.0.0`
+## 7.2.6
-#### Removed:
+**🔄 Modified:**
+
+* `Country::findCountries` → fix bloomer
+
+## 7.2.0
+
+**🔄 Modified:**
+
+* Re-write the sample project
+
+## 7.1.1
+
+**🔄 Modified:**
+
+* `minSdkVersion` → `23`
+
+## 7.1.0
+
+**⤵️ Added:**
+
+* New logo :D
+* New README :D
+* Text listener callbacks now return a `tailPlaceholder` for the value to be completed
+* `Country`: a model object representing a country with phone formatting, ISO codes & emojis
+* `Country.all`: a dictionary of known countries
+* `PhoneInputListener`: a `MaskedTextChangedListener` allowing to enter a phone number of any known country
+* `NumberInputListener`: a `MaskedTextChangedListener` allowing to enter currencies and other numbers
+
+**🔄 Modified:**
+
+* `minSdkVersion` → `30`
+
+## 6.1.0
+
+**⤴️ Removed:**
+
+* `IndexOutOfBoundsException`
+
+HUZZAH!
+
+## 6.0.0
+
+**⤴️ Removed:**
* `Mask::apply()`, the `autocomplete` flag
This flag is now a part of the `CaretGravity.FORWARD`.
-#### Modified:
+**🔄 Modified:**
* `CaretGravity` is now a sealed class
-#### Added:
+**⤵️ Added:**
* `CaretGravity.FORWARD`, the `autocomplete` flag
* `CaretGravity.BACKWARD`, the [`autoskip`](https://github.com/RedMadRobot/input-mask-android/wiki/0.-Mask#autoskip-flag) flag
-### `5.0.0`
+## 5.0.0
-#### Removed:
+**⤴️ Removed:**
* `CaretStringIterator::beforeCaret()`
This method is now replaced with `::insertionAffectsCaret()` and `::deletionAffectsCaret()` calls.
-#### Added:
+**⤵️ Added:**
* `CaretString` instances now contain caret gravity.
@@ -39,26 +81,26 @@ These methods allow to incorporate new caret gravity setting.
* Right-to-left masks.
-### `4.3.0`
+## 4.3.0
-#### Added:
+**⤵️ Added:**
* `AffinityCalculationStrategy.EXTRACTED_VALUE_CAPACITY` option allowing to have radically different mask format depending on the extracted value length
-### `4.2.0`
+## 4.2.0
-#### Added:
+**⤵️ Added:**
* `AffinityCalculationStrategy.CAPACITY` affinity calculation option allowing to have radically different mask format depending on the input length
-### `4.1.0`
+## 4.1.0
-#### Added:
+**⤵️ Added:**
* `formattedText` to `MaskedTextChangedListener.ValueListener::onTextChanged`
* by [Nikita Barishok](https://github.com/nbarishok) in [PR#73](https://github.com/RedMadRobot/input-mask-android/pull/73)
* `Mask::isValid(format:customNotations:)` method for format checks
-#### Fixed:
+**🔄 Fixed:**
* Optional blocks of symbols are now ignored when extracted value completeness is calculated, see [#70](https://github.com/RedMadRobot/input-mask-android/issues/70)
diff --git a/Documentation/Assets/logo.png b/Documentation/Assets/logo.png
new file mode 100644
index 0000000..9e0ed5a
Binary files /dev/null and b/Documentation/Assets/logo.png differ
diff --git a/Documentation/Assets/logo.xcf b/Documentation/Assets/logo.xcf
new file mode 100644
index 0000000..d620519
Binary files /dev/null and b/Documentation/Assets/logo.xcf differ
diff --git a/LICENSE b/LICENSE
index 00bf69e..e98e758 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
-The MIT License (MIT)
+MIT License
-Copyright (c) 2015 Redmadrobot
+Copyright (c) 2023 YEHOR TAFLANIDI
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-
diff --git a/README.md b/README.md
index b55c844..05e691e 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,33 @@
-
-
-[](https://github.com/sindresorhus/awesome)
-[](https://android-arsenal.com/details/1/4642)
-[](https://bintray.com/redmadrobot-opensource/android/input-mask-android/_latestVersion)
-[](https://codebeat.co/projects/github-com-redmadrobot-input-mask-android-master)
-[]()
-
-[]()[](https://github.com/RedMadRobot/input-mask-android)[](https://github.com/RedMadRobot/input-mask-ios)[](https://github.com/RedMadRobot/input-mask-ios)
-
-
-
-More GIFs [~3 MB]
-
-
- 
-
-
-
-
-### Migration Guide: v.6
-
-This update brings breaking changes. Namely, the `autocomplete` flag is now a part of the `CaretGravity` enum, thus the `Mask::apply` call is now single-argument, as all the necessary information is included into the `CaretString` structure.
-
-`v.6` introduces the «autoskip» feature, which allows the cursor to jump over formatting blocks of symbols in the middle of the text as if they were a single char when hitting `Backspace`, and this feature also allows to trim formatting characters on backspacing at the end of the line.
-
-Make sure to take a look at our [CHANGELOG](https://github.com/RedMadRobot/input-mask-android/blob/master/CHANGELOG.md).
-
-## Description
-
-`Input Mask` is an [Android](https://github.com/RedMadRobot/input-mask-android) & [iOS](https://github.com/RedMadRobot/input-mask-ios) native library allowing to format user input on the fly.
-
-The library provides you with a text field listener; when attached, it puts separators into the text while user types it in, and gets rid of unwanted symbols, all according to custom predefined pattern.
-
-This allows to reformat whole strings pasted from the clipboard, e.g. turning pasted `8 800 123-45-67` into
-`8 (800) 123 45 67`.
-
-Each pattern allows to extract valuable symbols from the entered text, returning you the immediate result with the text field listener's callback when the text changes. Such that, you'll be able to extract `1234567` from `8 (800) 123 45 67` or `19991234567` from `1 (999) 123 45 67` with two different patterns.
-
-All separators and valuable symbol placeholders have their own syntax. We call such patterns "masks".
+
-Mask examples:
+[](https://android-arsenal.com/details/1/4642) [](https://jitpack.io/#RedMadRobot/input-mask-android) [](https://github.com/JStumpp/awesome-android) [](https://github.com/RedMadRobot/input-mask-android/actions/workflows/android.yml) [](https://github.com/RedMadRobot/input-mask-ios) [](https://t.me/jeorge_taflanidi) [](#license)
-1. International phone numbers: `+1 ([000]) [000] [00] [00]`
-2. Local phone numbers: `([000]) [000]-[00]-[00]`
-3. Names: `[A][-----------------------------------------------------]`
-4. Text: `[A…]`
-5. Dates: `[00]{.}[00]{.}[9900]`
-6. Serial numbers: `[AA]-[00000099]`
-7. IPv4: `[099]{.}[099]{.}[099]{.}[099]`
-8. Visa card numbers: `[0000] [0000] [0000] [0000]`
-9. MM/YY: `[00]{/}[00]`
-10. UK IBAN: `GB[00] [____] [0000] [0000] [0000] [00]`
+Input masks restrict data input and allow you to guide users to enter correct values.
+Check out our [wiki](https://github.com/RedMadRobot/input-mask-android/wiki) for quick start and further reading.
-## Questions & Issues
+## ⚙️ Features
-Check out our [wiki](https://github.com/RedMadRobot/input-mask-android/wiki) for further reading.
-Please also take a closer look at our [Known issues](#knownissues) section before you incorporate our library into your project.
+- Apply formatting to your text fields, see [examples](#examples)
+- Filter out nonessential symbols (e.g. extract `0123456` from `+1 (999) 012-34-56`)
+- For international phone numbers
+ - guess the country from the entered digits
+ - apply corresponding value restrictions (e.g. a 🇺🇸US phone will have a format like `+1 201 456-7890`)
+- Apply number/currency formatting
-For your bugreports and feature requests please file new issues as usually.
+
-Should you have any questions, search for closed [issues](https://github.com/RedMadRobot/input-mask-android/issues?q=is%3Aclosed) or open new ones at **[StackOverflow](https://stackoverflow.com/questions/tagged/input-mask)** with the `input-mask` tag.
+## 💳 Examples
-We also have a community-driven [cookbook](https://github.com/RedMadRobot/input-mask-android/blob/master/Documentation/COOKBOOK.md) of recipes, be sure to check it out, too.
+- Phone numbers: `+1 ([000]) [000] [00] [00]`
+- Dates: `[00]{.}[00]{.}[9900]`
+- Serial numbers: `[AA]-[00000099]`
+- IPv4: `[099]{.}[099]{.}[099]{.}[099]`
+- Visa/MasterCard numbers: `[0000] [0000] [0000] [0000]`
+- UK IBAN: `GB[00] [____] [0000] [0000] [0000] [00]`
-## Installation
+## 🛠️ Installation
### Gradle
@@ -73,19 +35,28 @@ Make sure you've added Kotlin support to your project.
```gradle
repositories {
- jcenter()
+ maven { url 'https://jitpack.io' }
}
dependencies {
- implementation 'com.redmadrobot:input-mask-android:6.0.0'
+ implementation 'com.redmadrobot:input-mask-android:7.2.4'
implementation 'org.jetbrains.kotlin:kotlin-stdlib:$latest_version'
}
```
+## 📢 Communication, Questions & Issues
+
+Please take a closer look at our [Known issues](#knownissues) section before you incorporate our library into your project.
+
+For your bugreports and feature requests please file new issues [via GitHub](https://github.com/RedMadRobot/input-mask-android/issues/new/choose).
+
+Should you have any questions, please search for closed [issues](https://github.com/RedMadRobot/input-mask-android/issues?q=is%3Aclosed) or ask questions at **[StackOverflow](https://stackoverflow.com/questions/tagged/input-mask)** with the `input-mask` tag.
+
-# Known issues
+## ❗Known issues
+
## InputMask vs. `NoClassDefFoundError`
```
@@ -152,13 +123,7 @@ editText.setFilters(filters);
Bare in mind, you might have to befriend this solution with your existing `android:digits` [property](#inputmask-vs-androidinputtype-and-indexoutofboundsexception) in case your text field accepts both digits and letters.
-## References
-
-The list of projects that are using this library which were kind enough to share that information.
-
-Feel free to add yours below.
-
-## Special thanks
+## 🙏 Special thanks
These folks rock:
@@ -169,6 +134,6 @@ These folks rock:
* Vladislav [Shipaaaa](https://github.com/Shipaaaa) Shipugin
* Vadim [vkotovv](https://github.com/vkotovv) Kotov
-# License
+## ♻️ License
-The library is distributed under the MIT [LICENSE](https://opensource.org/licenses/MIT).
+The library is distributed under the MIT [LICENSE](https://github.com/RedMadRobot/input-mask-android/blob/master/LICENSE).
diff --git a/app/build.gradle b/app/build.gradle
index af594f5..faccb37 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,26 +1,40 @@
-apply plugin: 'com.android.application'
+plugins {
+ id 'com.android.application'
+ id 'org.jetbrains.kotlin.android'
+}
android {
- compileSdkVersion 28
+ namespace 'com.redmadrobot.sample'
+ compileSdk 33
defaultConfig {
applicationId "com.redmadrobot.sample"
- minSdkVersion 14
- targetSdkVersion 28
+ minSdk 30
+ targetSdk 33
versionCode 1
versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
+
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
}
dependencies {
- implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation deps.kotlin.stdlib
- implementation 'androidx.appcompat:appcompat:1.0.2'
- implementation project(':inputmask')
-}
+ implementation project(":inputmask")
+ implementation 'androidx.core:core-ktx:1.10.0'
+ implementation 'com.google.android.material:material:1.8.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 3ee60e8..481bb43 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,17 +1,21 @@
# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /Users/maximefimov/sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
-# Add any project specific keep options here:
-
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/redmadrobot/sample/SampleInstrumentedTest.kt b/app/src/androidTest/java/com/redmadrobot/sample/SampleInstrumentedTest.kt
new file mode 100644
index 0000000..1cdacf4
--- /dev/null
+++ b/app/src/androidTest/java/com/redmadrobot/sample/SampleInstrumentedTest.kt
@@ -0,0 +1,70 @@
+package com.redmadrobot.sample
+
+import android.view.View
+import android.widget.EditText
+import android.widget.TextView
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.typeText
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.hamcrest.Description
+import org.hamcrest.Matcher
+import org.hamcrest.TypeSafeMatcher
+import org.junit.Assert.*
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Sample app UI tests.
+ *
+ * @author taflanidi
+ */
+@RunWith(AndroidJUnit4::class)
+class SampleInstrumentedTest {
+ @get: Rule
+ var activityRule = ActivityScenarioRule(MainActivity::class.java)
+
+ @Test
+ fun testCurrencyField_enter12345point678_showsDollar12comma345point678() {
+ onView(withId(R.id.currency_edit_text))
+ .perform(typeText("12345.678"))
+ .check(matches(hasValueEqualTo("$12,345.678")))
+ }
+
+ @Test
+ fun testDateField_enter1point021989_shows1point02point1989() {
+ onView(withId(R.id.date_edit_text))
+ .perform(typeText("1.021989"))
+ .check(matches(hasValueEqualTo("1.02.1989")))
+ }
+
+ @Test
+ fun testPhoneField_enter38123456789_showsPlus380SpaceBracket12SpaceBracketSpace345Dash67Dash89() {
+ onView(withId(R.id.phone_edit_text))
+ .perform(typeText("381234567890"))
+ .check(matches(hasValueEqualTo("+380 (12) 345-67-89")))
+ }
+
+ private fun hasValueEqualTo(content: String): Matcher? {
+ return object : TypeSafeMatcher() {
+ override fun describeTo(description: Description) {
+ description.appendText("Has EditText/TextView the value: $content")
+ }
+
+ override fun matchesSafely(view: View?): Boolean {
+ if (view !is TextView && view !is EditText) {
+ return false
+ }
+ val text: String = if (view is TextView) {
+ view.text.toString()
+ } else {
+ (view as EditText).text.toString()
+ }
+ return text.equals(content, ignoreCase = true)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 65082c3..11f0fd8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,20 +1,23 @@
-
+
+
-
-
+ android:supportsRtl="true"
+ android:theme="@style/Theme.Sample"
+ tools:targetApi="31">
+
-
diff --git a/app/src/main/java/com/redmadrobot/sample/MainActivity.java b/app/src/main/java/com/redmadrobot/sample/MainActivity.java
deleted file mode 100644
index 09bcc2d..0000000
--- a/app/src/main/java/com/redmadrobot/sample/MainActivity.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.redmadrobot.sample;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import com.redmadrobot.inputmask.MaskedTextChangedListener;
-import com.redmadrobot.inputmask.helper.AffinityCalculationStrategy;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Home screen for the sample app.
- *
- * @author taflanidi
- */
-public final class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- setupPrefixSample();
- setupSuffixSample();
- }
-
- private void setupPrefixSample() {
- final EditText editText = findViewById(R.id.prefix_edit_text);
- final CheckBox checkBox = findViewById(R.id.prefix_check_box);
- final List affineFormats = new ArrayList<>();
- affineFormats.add("8 ([000]) [000]-[00]-[00]");
-
- final MaskedTextChangedListener listener = MaskedTextChangedListener.Companion.installOn(
- editText,
- "+7 ([000]) [000]-[00]-[00]",
- affineFormats,
- AffinityCalculationStrategy.PREFIX,
- new MaskedTextChangedListener.ValueListener() {
- @Override
- public void onTextChanged(boolean maskFilled, @NonNull final String extractedValue, @NonNull String formattedText) {
- logValueListener(maskFilled, extractedValue, formattedText);
- checkBox.setChecked(maskFilled);
- }
- }
- );
-
- editText.setHint(listener.placeholder());
- }
-
- private void setupSuffixSample() {
- final EditText editText = findViewById(R.id.suffix_edit_text);
- final CheckBox checkBox = findViewById(R.id.suffix_check_box);
- final List affineFormats = new ArrayList<>();
- affineFormats.add("+7 ([000]) [000]-[00]-[00]#[000]");
-
- final MaskedTextChangedListener listener = MaskedTextChangedListener.Companion.installOn(
- editText,
- "+7 ([000]) [000]-[00]-[00]",
- affineFormats,
- AffinityCalculationStrategy.WHOLE_STRING,
- new MaskedTextChangedListener.ValueListener() {
- @Override
- public void onTextChanged(boolean maskFilled, @NonNull final String extractedValue, @NonNull String formattedText) {
- logValueListener(maskFilled, extractedValue, formattedText);
- checkBox.setChecked(maskFilled);
- }
- }
- );
-
- editText.setHint(listener.placeholder());
- }
-
- private void logValueListener(boolean maskFilled, @NonNull String extractedValue, @NonNull String formattedText) {
- final String className = MainActivity.class.getSimpleName();
- Log.d(className, extractedValue);
- Log.d(className, String.valueOf(maskFilled));
- Log.d(className, formattedText);
- }
-
-}
diff --git a/app/src/main/java/com/redmadrobot/sample/MainActivity.kt b/app/src/main/java/com/redmadrobot/sample/MainActivity.kt
new file mode 100644
index 0000000..52cae4d
--- /dev/null
+++ b/app/src/main/java/com/redmadrobot/sample/MainActivity.kt
@@ -0,0 +1,137 @@
+package com.redmadrobot.sample
+
+import android.graphics.Paint
+import android.graphics.Rect
+import android.icu.util.Currency
+import android.os.Bundle
+import android.util.Log
+import android.view.ViewGroup.MarginLayoutParams
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import com.redmadrobot.inputmask.MaskedTextChangedListener.Companion.installOn
+import com.redmadrobot.inputmask.MaskedTextChangedListener.ValueListener
+import com.redmadrobot.inputmask.NumberInputListener
+import com.redmadrobot.inputmask.PhoneInputListener
+import com.redmadrobot.inputmask.helper.AffinityCalculationStrategy
+
+/**
+ * Home screen for the sample app.
+ *
+ * @author taflanidi
+ */
+class MainActivity : AppCompatActivity() {
+ private var listener: PhoneInputListener? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ setupCurrencySample()
+ setupDateSample()
+ setupPhoneSample()
+ }
+
+ private fun setupCurrencySample() {
+ val editText = findViewById(R.id.currency_edit_text)
+ val checkBox = findViewById(R.id.currency_check_box)
+ val listener = NumberInputListener.installOn(
+ editText,
+ object : ValueListener {
+ override fun onTextChanged(
+ maskFilled: Boolean,
+ extractedValue: String,
+ formattedValue: String,
+ tailPlaceholder: String
+ ) {
+ logValueListener(maskFilled, extractedValue, formattedValue)
+ checkBox.isChecked = maskFilled
+ }
+ }
+ )
+ listener.formatter = listener.formatter.unit(Currency.getInstance("USD"))
+ editText.hint = listener.placeholder()
+ }
+
+ private fun setupDateSample() {
+ val editText = findViewById(R.id.date_edit_text)
+ val checkBox = findViewById(R.id.date_check_box)
+ val placeholder = findViewById(R.id.date_placeholder_text_view)
+ val listener = installOn(
+ editText,
+ "[90].[90].[0000]",
+ ArrayList(),
+ ArrayList(),
+ AffinityCalculationStrategy.WHOLE_STRING,
+ autocomplete = true,
+ autoskip = true,
+ listener = null,
+ valueListener = object : ValueListener {
+ override fun onTextChanged(
+ maskFilled: Boolean,
+ extractedValue: String,
+ formattedValue: String,
+ tailPlaceholder: String
+ ) {
+ logValueListener(maskFilled, extractedValue, formattedValue)
+ checkBox.isChecked = maskFilled
+ placeholder.text = if (formattedValue.isEmpty()) "" else tailPlaceholder
+ val textBounds = Rect()
+ val paint: Paint = placeholder.paint
+ paint.getTextBounds(formattedValue, 0, formattedValue.length, textBounds)
+ val width = textBounds.width()
+ val placeholderParams = placeholder.layoutParams as MarginLayoutParams
+ placeholderParams.marginStart = width + 16 // 16 is an empirical value
+ }
+ }
+ )
+ editText.hint = listener.placeholder()
+ }
+
+ private fun setupPhoneSample() {
+ val editText = findViewById(R.id.phone_edit_text)
+ val checkBox = findViewById(R.id.phone_check_box)
+ val countriesTextView = findViewById(R.id.countries_text_view)
+ listener = PhoneInputListener.installOn(
+ editText,
+ autocomplete = true,
+ autoskip = false,
+ listener = null,
+ valueListener = object : ValueListener {
+ override fun onTextChanged(
+ maskFilled: Boolean,
+ extractedValue: String,
+ formattedValue: String,
+ tailPlaceholder: String
+ ) {
+ logValueListener(maskFilled, extractedValue, formattedValue)
+ checkBox.isChecked = maskFilled
+ val countriesList = StringBuilder()
+ this@MainActivity.listener?.computedCountries?.forEach { country ->
+ countriesList
+ .append(country.countryCode)
+ .append(" ")
+ .append(country.emoji)
+ .append(" ")
+ .append(country.name)
+ .append("\n")
+ }
+ countriesTextView.text = countriesList.toString()
+ }
+ }
+ )
+ editText.hint = listener?.placeholder()
+ }
+
+ private fun logValueListener(
+ maskFilled: Boolean,
+ extractedValue: String,
+ formattedText: String
+ ) {
+ val className = MainActivity::class.java.simpleName
+ Log.d(className, extractedValue)
+ Log.d(className, maskFilled.toString())
+ Log.d(className, formattedText)
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 1d1e0e9..19d7d18 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,26 +1,32 @@
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp">
+ android:textStyle="bold"
+ android:textSize="20sp"
+ android:text="@string/currency_label" />
+ android:digits="1234567890., $€"
+ android:inputType="numberDecimal"
+ android:gravity="end"
+ tools:ignore="Autofill,LabelFor" />
+ android:textStyle="bold"
+ android:textSize="20sp"
+ android:text="@string/date_label" />
+
+
+
+
+
+
+
+
+
+
+
+
+ android:inputType="phone"
+ tools:ignore="Autofill,LabelFor" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..c0fd1e9
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f09a38b..6180c98 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,6 @@
- InputMask
- Phone Prefix Sample
- Phone Suffix Sample
+ Sample
+ Currency:
+ Date:
+ Phone:
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
deleted file mode 100644
index 766ab99..0000000
--- a/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..fb0958c
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 2a1ca04..37d2fb6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,23 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- apply from: "${rootProject.projectDir}/gradle/dependencies.gradle"
-
- addRepos(repositories)
-
- dependencies {
- classpath deps.gradle.android_plugin
- classpath deps.kotlin.plugin
- classpath deps.kotlin.dokka
- classpath deps.bintray.android_maven_plugin
- classpath deps.bintray.gradle_bintray_plugin
- }
+plugins {
+ id 'com.android.application' version '7.1.3' apply false
+ id 'com.android.library' version '7.1.3' apply false
+ id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
+ id 'maven-publish'
}
-
-allprojects {
- apply from: "${rootProject.projectDir}/gradle/version.gradle"
-
- addRepos(repositories)
-}
-
-
diff --git a/gradle.properties b/gradle.properties
index c1c84d8..3c5031e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,11 +6,18 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-android.enableJetifier=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle
deleted file mode 100644
index 6272c58..0000000
--- a/gradle/dependencies.gradle
+++ /dev/null
@@ -1,73 +0,0 @@
-static def addRepos(RepositoryHandler handler) {
- handler.google()
- handler.jcenter()
-}
-
-ext.addRepos = this.&addRepos
-
-//region Build versions
-def build_versions = [:]
-
-build_versions.min_sdk = 14
-build_versions.target_sdk = 28
-build_versions.compile_sdk = 28
-
-ext.build_versions = build_versions
-//endregion
-
-def versions = [:]
-
-ext.deps = [:]
-def deps = [:]
-
-//region Gradle
-def gradle = [:]
-
-versions.android_plugin = "3.3.2"
-
-gradle.android_plugin = "com.android.tools.build:gradle:$versions.android_plugin"
-
-deps.gradle = gradle
-//endregion
-
-//region Kotlin
-def kotlin = [:]
-
-versions.kotlin = "1.3.21"
-versions.dokka = "0.9.17"
-
-kotlin.stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin"
-kotlin.test = "org.jetbrains.kotlin:kotlin-test-junit:$versions.kotlin"
-kotlin.plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
-kotlin.dokka = "org.jetbrains.dokka:dokka-android-gradle-plugin:$versions.dokka"
-
-deps.kotlin = kotlin
-//endregion
-
-//region Testing
-def test = [:]
-
-versions.junit = "4.12"
-versions.assertj = "3.10.0"
-versions.mockito_kotlin = "2.0.0"
-
-test.junit = "junit:junit:$versions.junit"
-test.mockito_kotlin = "com.nhaarman.mockitokotlin2:mockito-kotlin:$versions.mockito_kotlin"
-test.assertj = "org.assertj:assertj-core:$versions.assertj"
-
-deps.test = test
-//endregion
-
-//region Bintray
-def bintray = [:]
-
-versions.maven_plugin = "2.0"
-versions.bintray_plugin = "1.8.4"
-
-bintray.android_maven_plugin = "com.github.dcendents:android-maven-gradle-plugin:$versions.maven_plugin"
-bintray.gradle_bintray_plugin = "com.jfrog.bintray.gradle:gradle-bintray-plugin:$versions.bintray_plugin"
-
-deps.bintray = bintray
-//endregion
-
-ext.deps = deps
\ No newline at end of file
diff --git a/gradle/publish.gradle b/gradle/publish.gradle
deleted file mode 100644
index 8d2acd6..0000000
--- a/gradle/publish.gradle
+++ /dev/null
@@ -1,74 +0,0 @@
-apply plugin: 'com.github.dcendents.android-maven'
-
-def publishPropertiesFile = rootProject.file("gradle/publish.properties")
-def publishProperties = new Properties()
-
-if (publishPropertiesFile.canRead()) {
- publishProperties.load(new FileInputStream(publishPropertiesFile))
-}
-apply plugin: 'maven-publish'
-apply plugin: 'com.jfrog.bintray'
-
-version publishProperties['lib_version']
-group publishProperties['group_id']
-
-task androidSourcesJar(type: Jar) {
- classifier = 'sources'
- from android.sourceSets.main.kotlin.srcDirs
-}
-
-publishing {
- publications {
- Production(MavenPublication) {
- artifact("$buildDir/outputs/aar/input-mask-android-release.aar")
- artifact androidSourcesJar
- groupId
- artifactId publishProperties['lib_name']
- version this.version
-
- pom.withXml {
- def dependenciesNode = asNode().appendNode('dependencies')
-
- configurations.implementation.allDependencies.each {
- if (it.name != 'unspecified') {
- def dependencyNode = dependenciesNode.appendNode('dependency')
- dependencyNode.appendNode('groupId', it.group)
- dependencyNode.appendNode('artifactId', it.name)
- dependencyNode.appendNode('version', it.version)
- }
- }
- }
- }
- }
-}
-
-bintray {
- user = publishProperties['user']
- key = publishProperties['api_key']
- publications = ['Production']
- configurations = ['archives']
- override = true
-
- pkg {
- repo = publishProperties['repository']
- name = publishProperties['lib_name']
- description = publishProperties['lib_description']
- userOrg = publishProperties['organization_id']
- licenses = ['MIT']
- websiteUrl = publishProperties['lib_website']
- vcsUrl = publishProperties['lib_vcs']
- issueTrackerUrl = publishProperties['lib_issue_tracker']
- publish = true
- publicDownloadNumbers = true
-
- // set as true to test uploading
- dryRun = true
-
- version {
- name = this.version
- released = new Date()
- vcsTag = this.version
- }
- }
-}
-
diff --git a/gradle/version.gradle b/gradle/version.gradle
deleted file mode 100644
index 3ec56f2..0000000
--- a/gradle/version.gradle
+++ /dev/null
@@ -1,21 +0,0 @@
-def getVersionCodeFromProperties() {
- Properties versionProperties = loadVersionProperties()
- return (versionProperties["version_code"] ?: "0").toString().toInteger()
-}
-
-def getVersionNameFromProperties() {
- Properties versionProperties = loadVersionProperties()
- return versionProperties["version_name"]
-}
-
-private Properties loadVersionProperties() {
- Properties versionProperties = new Properties()
- //noinspection GroovyAssignabilityCheck
- versionProperties.load(project.rootProject.file('version.properties').newDataInputStream())
- versionProperties
-}
-
-ext {
- getVersionCodeFromProperties = this.&getVersionCodeFromProperties
- getVersionNameFromProperties = this.&getVersionNameFromProperties
-}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64..e708b1c 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a4d5bf4..55c9da8 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Mar 12 18:40:51 MSK 2019
+#Mon Apr 17 15:07:31 GET 2023
distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
+zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 91a7e26..4f906e0 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,20 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# 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
+#
+# https://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.
+#
##############################################################################
##
@@ -6,20 +22,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +64,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,33 +75,14 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -90,7 +106,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -110,11 +126,13 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
@@ -138,27 +156,30 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index aec9973..ac1b06f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -8,20 +24,23 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,34 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/inputmask/build.gradle b/inputmask/build.gradle
index 614720a..3108a2c 100644
--- a/inputmask/build.gradle
+++ b/inputmask/build.gradle
@@ -1,66 +1,51 @@
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'org.jetbrains.dokka'
-
-apply from: '../gradle/publish.gradle'
+plugins {
+ id 'com.android.library'
+ id 'org.jetbrains.kotlin.android'
+}
android {
- compileSdkVersion build_versions.compile_sdk
+ namespace 'com.redmadrobot.inputmask'
+ compileSdk 33
defaultConfig {
- minSdkVersion build_versions.min_sdk
- targetSdkVersion build_versions.target_sdk
+ minSdk 24
+ targetSdk 33
- archivesBaseName = "input-mask-android"
-
- versionCode getVersionCodeFromProperties()
- versionName getVersionNameFromProperties()
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
- sourceSets {
- main.java.srcDirs += 'src/main/kotlin'
-
- androidTest.java.srcDirs += 'src/androidTest/kotlin'
- test.java.srcDirs += 'src/test/kotlin'
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
}
- dokka {
- outputFormat = 'html'
- outputDirectory = "$buildDir/documentation"
-
- reportUndocumented = false
- includeNonPublic = true
- skipEmptyPackages = false
-
- includes = ['module-info.md']
-
- sourceDirs = files('src/main/kotlin')
- kotlinTasks {
- // Workaround to avoid generating unnecessary documentation
- }
+ kotlinOptions {
+ jvmTarget = '1.8'
}
}
dependencies {
- implementation deps.kotlin.stdlib
-
- testImplementation deps.test.junit
-}
-
-task dokkaMarkdown(type: org.jetbrains.dokka.gradle.DokkaTask) {
- outputFormat = 'markdown'
- outputDirectory = "$buildDir/markdowndoc"
+ implementation 'androidx.core:core-ktx:1.10.0'
+ testImplementation 'junit:junit:4.13.2'
}
-task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
- outputFormat = 'javadoc'
- outputDirectory = "$buildDir/javadoc"
+afterEvaluate {
+ publishing {
+ publications {
+ release(MavenPublication) {
+ from components.release
+ groupId = 'com.redmadrobot'
+ artifactId = 'inputmask'
+ version = '7.2.4'
+ }
+ }
+ }
}
-
diff --git a/inputmask/consumer-rules.pro b/inputmask/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/inputmask/proguard-rules.pro b/inputmask/proguard-rules.pro
index 3ee60e8..481bb43 100644
--- a/inputmask/proguard-rules.pro
+++ b/inputmask/proguard-rules.pro
@@ -1,17 +1,21 @@
# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /Users/maximefimov/sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
-# Add any project specific keep options here:
-
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/inputmask/src/main/AndroidManifest.xml b/inputmask/src/main/AndroidManifest.xml
index 64678ab..bdae66c 100644
--- a/inputmask/src/main/AndroidManifest.xml
+++ b/inputmask/src/main/AndroidManifest.xml
@@ -1,3 +1,2 @@
-
-
+
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/MaskedTextChangedListener.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/MaskedTextChangedListener.kt
index 0668e39..bf687a9 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/MaskedTextChangedListener.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/MaskedTextChangedListener.kt
@@ -2,6 +2,7 @@ package com.redmadrobot.inputmask
import android.text.Editable
import android.text.TextWatcher
+import android.util.Log
import android.view.View
import android.widget.EditText
import com.redmadrobot.inputmask.helper.AffinityCalculationStrategy
@@ -33,7 +34,12 @@ open class MaskedTextChangedListener(
) : TextWatcher, View.OnFocusChangeListener {
interface ValueListener {
- fun onTextChanged(maskFilled: Boolean, extractedValue: String, formattedValue: String)
+ fun onTextChanged(
+ maskFilled: Boolean,
+ extractedValue: String,
+ formattedValue: String,
+ tailPlaceholder: String
+ )
}
private val primaryMask: Mask
@@ -129,7 +135,7 @@ open class MaskedTextChangedListener(
val result = setText(text, it, autocomplete)
this.afterText = result.formattedText.string
this.caretPosition = result.formattedText.caretPosition
- this.valueListener?.onTextChanged(result.complete, result.extractedValue, afterText)
+ this.valueListener?.onTextChanged(result.complete, result.extractedValue, afterText, result.tailPlaceholder)
return result
}
}
@@ -146,7 +152,22 @@ open class MaskedTextChangedListener(
with(field) {
setText(result.formattedText.string)
- setSelection(result.formattedText.caretPosition)
+
+ try {
+ setSelection(result.formattedText.caretPosition)
+ } catch (e: java.lang.IndexOutOfBoundsException) {
+ Log.e(
+ "input-mask-android",
+ """
+
+ WARNING! Your text field is not configured for the MaskedTextChangedListener!
+ For more information please refer to
+
+ InputMask vs. android:inputType and IndexOutOfBoundsException
+ https://github.com/RedMadRobot/input-mask-android#inputmask-vs-androidinputtype-and-indexoutofboundsexception
+ """
+ )
+ }
}
return result
@@ -157,7 +178,7 @@ open class MaskedTextChangedListener(
*
* @return Placeholder string.
*/
- fun placeholder(): String = this.primaryMask.placeholder()
+ open fun placeholder(): String = this.primaryMask.placeholder()
/**
* Minimal length of the text inside the field to fill all mandatory characters in the mask.
@@ -190,7 +211,23 @@ open class MaskedTextChangedListener(
override fun afterTextChanged(edit: Editable?) {
this.field.get()?.removeTextChangedListener(this)
edit?.replace(0, edit.length, this.afterText)
- this.field.get()?.setSelection(this.caretPosition)
+
+ try {
+ this.field.get()?.setSelection(this.caretPosition)
+ } catch (e: IndexOutOfBoundsException) {
+ Log.e(
+ "input-mask-android",
+ """
+
+ WARNING! Your text field is not configured for the MaskedTextChangedListener!
+ For more information please refer to
+
+ InputMask vs. android:inputType and IndexOutOfBoundsException
+ https://github.com/RedMadRobot/input-mask-android#inputmask-vs-androidinputtype-and-indexoutofboundsexception
+ """
+ )
+ }
+
this.field.get()?.addTextChangedListener(this)
this.listener?.afterTextChanged(edit)
}
@@ -215,7 +252,7 @@ open class MaskedTextChangedListener(
this.afterText = result.formattedText.string
this.caretPosition = result.formattedText.caretPosition
- this.valueListener?.onTextChanged(result.complete, result.extractedValue, afterText)
+ this.valueListener?.onTextChanged(result.complete, result.extractedValue, afterText, result.tailPlaceholder)
}
override fun onFocusChange(view: View?, hasFocus: Boolean) {
@@ -234,12 +271,27 @@ open class MaskedTextChangedListener(
this.afterText = result.formattedText.string
this.caretPosition = result.formattedText.caretPosition
this.field.get()?.setText(afterText)
- this.field.get()?.setSelection(result.formattedText.caretPosition)
- this.valueListener?.onTextChanged(result.complete, result.extractedValue, afterText)
+
+ try {
+ this.field.get()?.setSelection(result.formattedText.caretPosition)
+ } catch (e: IndexOutOfBoundsException) {
+ Log.e(
+ "input-mask-android",
+ """
+
+ WARNING! Your text field is not configured for the MaskedTextChangedListener!
+ For more information please refer to
+
+ InputMask vs. android:inputType and IndexOutOfBoundsException
+ https://github.com/RedMadRobot/input-mask-android#inputmask-vs-androidinputtype-and-indexoutofboundsexception
+ """
+ )
+ }
+ this.valueListener?.onTextChanged(result.complete, result.extractedValue, afterText, result.tailPlaceholder)
}
}
- private fun pickMask(
+ open fun pickMask(
text: CaretString
): Mask {
if (this.affineFormats.isEmpty()) return this.primaryMask
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/NumberInputListener.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/NumberInputListener.kt
new file mode 100644
index 0000000..6bf8970
--- /dev/null
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/NumberInputListener.kt
@@ -0,0 +1,254 @@
+package com.redmadrobot.inputmask
+
+import android.icu.number.LocalizedNumberFormatter
+import android.icu.number.NumberFormatter
+import android.icu.number.Precision
+import android.os.Build
+import android.text.TextWatcher
+import android.widget.EditText
+import androidx.annotation.RequiresApi
+import com.redmadrobot.inputmask.helper.AffinityCalculationStrategy
+import com.redmadrobot.inputmask.helper.Mask
+import com.redmadrobot.inputmask.model.CaretString
+import com.redmadrobot.inputmask.model.Notation
+import java.math.RoundingMode
+import java.util.*
+
+/**
+ * — Mom, can we have a neural network?
+ * — No, we have a neural network at home.
+ *
+ * Neural network at home:
+ */
+
+/**
+ * ### NumberInputListener
+ *
+ * A ``MaskedTextInputListener`` subclass for numbers.
+ *
+ * Use with caution, this module is still in development.
+ *
+ * - seealso: the ``NumberInputListener/formatter`` field
+ */
+@RequiresApi(Build.VERSION_CODES.R)
+open class NumberInputListener(
+ primaryFormat: String,
+ affineFormats: List = emptyList(),
+ customNotations: List = emptyList(),
+ affinityCalculationStrategy: AffinityCalculationStrategy = AffinityCalculationStrategy.WHOLE_STRING,
+ autocomplete: Boolean = true,
+ autoskip: Boolean = false,
+ field: EditText,
+ listener: TextWatcher? = null,
+ valueListener: ValueListener? = null,
+ rightToLeft: Boolean = false
+): MaskedTextChangedListener(
+ primaryFormat,
+ affineFormats,
+ customNotations,
+ affinityCalculationStrategy,
+ autocomplete,
+ autoskip,
+ field,
+ listener,
+ valueListener,
+ rightToLeft
+) {
+ /**
+ * Convenience constructor.
+ */
+ constructor(field: EditText):
+ this(field, null)
+
+ /**
+ * Convenience constructor.
+ */
+ constructor(field: EditText, valueListener: ValueListener?):
+ this(field, null, valueListener)
+
+ /**
+ * Convenience constructor.
+ */
+ constructor(field: EditText, listener: TextWatcher?, valueListener: ValueListener?):
+ this(true, false, field, listener, valueListener)
+
+ /**
+ * Convenience constructor.
+ */
+ constructor(
+ autocomplete: Boolean,
+ autoskip: Boolean,
+ field: EditText,
+ listener: TextWatcher?,
+ valueListener: ValueListener?
+ ):
+ this(
+ "",
+ emptyList(),
+ emptyList(),
+ AffinityCalculationStrategy.WHOLE_STRING,
+ autocomplete,
+ autoskip,
+ field,
+ listener,
+ valueListener
+ )
+
+ open var formatter: LocalizedNumberFormatter =
+ NumberFormatter
+ .withLocale(Locale("en_us"))
+ .roundingMode(RoundingMode.FLOOR)
+ .precision(Precision.unlimited())
+
+ override fun placeholder(): String {
+ val text = "0"
+ val mask = pickMask(
+ CaretString(text, text.length, CaretString.CaretGravity.FORWARD(autocomplete))
+ )
+ return mask.placeholder()
+ }
+
+ override fun pickMask(text: CaretString): Mask {
+ val sanitisedNumberString = extractNumberAndDecimalSeparator(
+// formatter,
+ text.string
+ )
+
+ val intNum = sanitisedNumberString.intPart.toLong()
+ val intMaskFormat = formatter.format(intNum)
+
+ val intZero = intNum == 0.toLong()
+ val notationChar = assignNonZeroNumberNotation()
+
+ var maskFormat = ""
+ var first = true
+ intMaskFormat.toString().forEach { c: Char ->
+ if (c.isDigit()) {
+ if (first && !intZero) {
+ maskFormat += "[$notationChar]"
+ first = false
+ } else {
+ maskFormat += "[0]"
+ }
+ } else {
+ maskFormat += "{$c}"
+ }
+ }
+
+ if (sanitisedNumberString.numberOfOccurrencesOfDecimalSeparator > 0) {
+ maskFormat += "{${sanitisedNumberString.expectedDecimalSeparator}}"
+ }
+
+ sanitisedNumberString.decPart.forEach {
+ maskFormat += "[0]"
+ }
+
+ primaryFormat = maskFormat
+ return super.pickMask(text)
+ }
+
+ private data class SanitisedNumberString(
+ val intPart: String,
+ val decPart: String,
+ val expectedDecimalSeparator: String,
+ val numberOfOccurrencesOfDecimalSeparator: Int
+ )
+
+ private fun extractNumberAndDecimalSeparator(
+// formatter: LocalizedNumberFormatter,
+ text: String
+ ): SanitisedNumberString {
+ val expectedDecimalSeparator: String = decimalSeparator
+
+ var digitsAndDecimalSeparators = text.filter { c: Char -> c.isDigit() || c.toString() == decimalSeparator }
+
+ val numberOfOccurencesOfDecimalSeparator = digitsAndDecimalSeparators.count { c: Char -> c.toString() == decimalSeparator }
+ if (numberOfOccurencesOfDecimalSeparator > 1) {
+ var numberOfReplacements = numberOfOccurencesOfDecimalSeparator - 1
+ digitsAndDecimalSeparators = digitsAndDecimalSeparators.reversed().filter { c: Char ->
+ if (!c.isDigit() && numberOfReplacements > 0) {
+ numberOfReplacements -= 1
+ return@filter false
+ }
+ true
+ }.reversed()
+ }
+
+ val components = digitsAndDecimalSeparators.split(decimalSeparator)
+
+ var intStr: String
+ var decStr = ""
+
+ if (components.size > 1) {
+ intStr = components.first()
+ decStr = components.last()
+ } else {
+ intStr = components.first()
+ }
+
+ intStr = if (intStr.isEmpty()) "0" else intStr
+// intStr = String(intStr.prefix(formatter.maximumIntegerDigits)) TODO
+// decStr = String(decStr.prefix(formatter.maximumFractionDigits)) TODO
+
+ return SanitisedNumberString(
+ intStr,
+ decStr,
+ expectedDecimalSeparator,
+ numberOfOccurencesOfDecimalSeparator
+ )
+ }
+
+ private fun assignNonZeroNumberNotation(): Char {
+ val character = '1'
+ customNotations = listOf(
+ Notation(
+ character,
+ "123456789",
+ false
+ )
+ )
+ return character
+ }
+
+ companion object {
+ val decimalSeparator = "."
+
+ /**
+ * Create a ``NumberInputListener`` instance and assign it as a field's
+ * `TextWatcher` and `onFocusChangeListener`.
+ */
+ fun installOn(
+ editText: EditText,
+ valueListener: ValueListener? = null
+ ): NumberInputListener = installOn(
+ editText,
+ true,
+ false,
+ null,
+ valueListener
+ )
+
+ /**
+ * Create a ``NumberInputListener`` instance and assign it as a field's
+ * `TextWatcher` and `onFocusChangeListener`.
+ */
+ fun installOn(
+ editText: EditText,
+ autocomplete: Boolean = true,
+ autoskip: Boolean = false,
+ listener: TextWatcher? = null,
+ valueListener: ValueListener? = null
+ ): NumberInputListener {
+ val maskedListener = NumberInputListener(
+ autocomplete,
+ autoskip,
+ editText,
+ listener,
+ valueListener
+ )
+ editText.addTextChangedListener(maskedListener)
+ editText.onFocusChangeListener = maskedListener
+ return maskedListener
+ }
+ }
+}
\ No newline at end of file
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/PhoneInputListener.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/PhoneInputListener.kt
new file mode 100644
index 0000000..f1587a4
--- /dev/null
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/PhoneInputListener.kt
@@ -0,0 +1,182 @@
+package com.redmadrobot.inputmask
+
+import android.text.TextWatcher
+import android.widget.EditText
+import com.redmadrobot.inputmask.helper.AffinityCalculationStrategy
+import com.redmadrobot.inputmask.helper.Mask
+import com.redmadrobot.inputmask.model.CaretString
+import com.redmadrobot.inputmask.model.Country
+import com.redmadrobot.inputmask.model.Notation
+
+/**
+ * ### PhoneInputListener
+ *
+ * A ``MaskedTextInputListener`` subclass for guessing a country based on the entered digit sequence
+ *
+ * Computed country dictates the phone formatting
+ */
+open class PhoneInputListener(
+ primaryFormat: String,
+ affineFormats: List = emptyList(),
+ customNotations: List = emptyList(),
+ affinityCalculationStrategy: AffinityCalculationStrategy = AffinityCalculationStrategy.WHOLE_STRING,
+ autocomplete: Boolean = true,
+ autoskip: Boolean = false,
+ field: EditText,
+ listener: TextWatcher? = null,
+ valueListener: ValueListener? = null,
+ rightToLeft: Boolean = false
+): MaskedTextChangedListener(
+ primaryFormat,
+ affineFormats,
+ customNotations,
+ affinityCalculationStrategy,
+ autocomplete,
+ autoskip,
+ field,
+ listener,
+ valueListener,
+ rightToLeft
+) {
+ /**
+ * Convenience constructor.
+ */
+ constructor(field: EditText):
+ this(field, null)
+
+ /**
+ * Convenience constructor.
+ */
+ constructor(field: EditText, valueListener: ValueListener?):
+ this(field, null, valueListener)
+
+ /**
+ * Convenience constructor.
+ */
+ constructor(field: EditText, listener: TextWatcher?, valueListener: ValueListener?):
+ this(true, false, field, listener, valueListener)
+
+ /**
+ * Convenience constructor.
+ */
+ constructor(
+ autocomplete: Boolean,
+ autoskip: Boolean,
+ field: EditText,
+ listener: TextWatcher?,
+ valueListener: ValueListener?
+ ):
+ this(
+ "",
+ emptyList(),
+ emptyList(),
+ AffinityCalculationStrategy.WHOLE_STRING,
+ autocomplete,
+ autoskip,
+ field,
+ listener,
+ valueListener
+ )
+
+ /**
+ * A detected ``Country`` based on the entered digits
+ */
+ var computedCountry: Country? = null
+
+ /**
+ * A list of possible ``Country`` candidates based on the entered digits
+ */
+ var computedCountries: List = listOf()
+
+ /**
+ * Allowed ``Country`` list. Pre-filters the ``Country::all`` dictionary.
+ *
+ * May contain country names, native country names, ISO-3166 codes, country emojis, or their mix.
+ *
+ * E.g.
+ * ```
+ * listener.enableCountries = listOf(
+ * "Greece",
+ * "BE",
+ * "🇪🇸"
+ * )
+ * ```
+ */
+ var enableCountries: List? = null
+
+ /**
+ * Blocked ``Country`` list. Pre-filters the ``Country::all`` dictionary.
+ *
+ * May contain country names, native country names, ISO-3166 codes, country emojis, or their mix.
+ *
+ * E.g.
+ * ```
+ * listener.disableCountries = listOf(
+ * "Greece",
+ * "BE",
+ * "🇪🇸"
+ * )
+ * ```
+ */
+ var disableCountries: List? = null
+
+ /**
+ A custom ``Country`` list to be used instead of ``Country::all`` dictionary.
+ */
+ var customCountries: List? = null
+
+ override fun pickMask(text: CaretString): Mask {
+ computedCountries = Country.findCountries(customCountries, enableCountries, disableCountries, text.string)
+ computedCountry = if (computedCountries.count() == 1) computedCountries.first() else null
+
+ val country = computedCountry
+ return if (country == null) {
+ Mask("+[000] [000] [000] [00] [00]")
+ } else {
+ primaryFormat = country.primaryFormat
+ affineFormats = country.affineFormats
+
+ super.pickMask(text)
+ }
+ }
+
+ companion object {
+ /**
+ * Create a ``PhoneInputListener`` instance and assign it as a field's
+ * `TextWatcher` and `onFocusChangeListener`.
+ */
+ fun installOn(
+ editText: EditText,
+ valueListener: ValueListener? = null
+ ): PhoneInputListener = installOn(
+ editText,
+ true,
+ false,
+ null,
+ valueListener
+ )
+
+ /**
+ * Create a ``PhoneInputListener`` instance and assign it as a field's
+ * `TextWatcher` and `onFocusChangeListener`.
+ */
+ fun installOn(
+ editText: EditText,
+ autocomplete: Boolean = true,
+ autoskip: Boolean = false,
+ listener: TextWatcher? = null,
+ valueListener: ValueListener? = null
+ ): PhoneInputListener {
+ val maskedListener = PhoneInputListener(
+ autocomplete,
+ autoskip,
+ editText,
+ listener,
+ valueListener
+ )
+ editText.addTextChangedListener(maskedListener)
+ editText.onFocusChangeListener = maskedListener
+ return maskedListener
+ }
+ }
+}
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/AffinityCalculationStrategy.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/AffinityCalculationStrategy.kt
index a8815d9..6b10358 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/AffinityCalculationStrategy.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/AffinityCalculationStrategy.kt
@@ -11,7 +11,7 @@ enum class AffinityCalculationStrategy {
/**
* Default strategy.
*
- * Uses ```Mask``` built-in mechanism to calculate total affinity between the text and the mask format.
+ * Uses ``Mask`` built-in mechanism to calculate total affinity between the text and the mask format.
*
* For example:
* ```
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/CaretStringIterator.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/CaretStringIterator.kt
index 017c5b6..2d7051a 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/CaretStringIterator.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/CaretStringIterator.kt
@@ -5,10 +5,10 @@ import com.redmadrobot.inputmask.model.CaretString
/**
* ### CaretStringIterator
*
- * Iterates over CaretString.string characters. Each ```next()``` call returns current character and
+ * Iterates over CaretString.string characters. Each `next()` call returns current character and
* adjusts iterator position.
*
- * ```CaretStringIterator``` is used by the ```Mask``` instance to iterate over the string that
+ * ``CaretStringIterator`` is used by the ``Mask`` instance to iterate over the string that
* should be formatted.
*
* @author taflanidi
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Compiler.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Compiler.kt
index 45bf076..9a41458 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Compiler.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Compiler.kt
@@ -8,27 +8,27 @@ import com.redmadrobot.inputmask.model.state.*
* ### Compiler
*
* Creates a sequence of states from the mask format string.
- * @see ```State``` class.
+ * @see ``State`` class.
*
- * @complexity ```O(formatString.characters.count)``` plus ```FormatSanitizer``` complexity.
+ * @complexity `O(formatString.characters.count)` plus ``FormatSanitizer`` complexity.
*
- * @requires Format string to contain only flat groups of symbols in ```[]``` and ```{}``` brackets
- * without nested brackets, like ```[[000]99]```. Also, ```[…]``` groups may contain only the
- * specified characters ("0", "9", "A", "a", "…", "_" and "-"). Square bracket ```[]``` groups cannot
+ * @requires Format string to contain only flat groups of symbols in `[]` and `{}` brackets
+ * without nested brackets, like `[[000]99]`. Also, `[…]` groups may contain only the
+ * specified characters ("0", "9", "A", "a", "…", "_" and "-"). Square bracket `[]` groups cannot
* contain mixed types of symbols ("0" and "9" with "A" and "a" or "_" and "-").
*
- * ```Compiler``` object is initialized and ```Compiler.compile(formatString:)``` is called during
- * the ```Mask``` instance initialization.
+ * ``Compiler`` object is initialized and ``Compiler.compile(formatString:)`` is called during
+ * the ``Mask`` instance initialization.
*
- * ```Compiler``` uses ```FormatSanitizer``` to prepare ```formatString``` for the compilation.
+ * ``Compiler`` uses ``FormatSanitizer`` to prepare `formatString` for the compilation.
*
* @author taflanidi
*/
class Compiler(
/**
- * A list of custom rules to compile square bracket ```[]``` groups of format symbols.
+ * A list of custom rules to compile square bracket `[]` groups of format symbols.
*
- * @see ```Notation``` class.
+ * @see ``Notation`` class.
*/
private val customNotations: List
) {
@@ -36,20 +36,20 @@ class Compiler(
/**
* ### FormatError
*
- * Compiler error exception type, thrown when ```formatString``` contains inappropriate
+ * Compiler error exception type, thrown when `formatString` contains inappropriate
* character sequences.
*
- * ```FormatError``` is used by the ```Compiler``` and ```FormatSanitizer``` classes.
+ * ``FormatError`` is used by the ``Compiler`` and ``FormatSanitizer`` classes.
*/
class FormatError : Exception()
/**
- * Compile ```formatString``` into the sequence of states.
+ * Compile `formatString` into the sequence of states.
*
- * * "Free" characters from ```formatString``` are converted to ```FreeState```-s.
- * * Characters in square brackets are converted to ```ValueState```-s and ```OptionalValueState```-s.
- * * Characters in curly brackets are converted to ```FixedState```-s.
- * * End of the formatString line makes ```EOLState```.
+ * * "Free" characters from `formatString` are converted to ``FreeState``-s.
+ * * Characters in square brackets are converted to ``ValueState``-s and ``OptionalValueState``-s.
+ * * Characters in curly brackets are converted to ``FixedState``-s.
+ * * End of the formatString line makes ``EOLState``.
*
* For instance,
*
@@ -74,17 +74,17 @@ class Compiler(
*
* @param formatString string with a mask format.
*
- * @see ```State``` class.
+ * @see ``State`` class.
*
- * @complexity ```O(formatString.characters.count)``` plus ```FormatSanitizer``` complexity.
+ * @complexity `O(formatString.characters.count)` plus ``FormatSanitizer`` complexity.
*
- * @requires: Format string to contain only flat groups of symbols in ```[]``` and ```{}``` brackets
- * without nested brackets, like ```[[000]99]```. Also, ```[…]``` groups may contain only the
+ * @requires: Format string to contain only flat groups of symbols in `[]` and `{}` brackets
+ * without nested brackets, like `[[000]99]`. Also, `[…]` groups may contain only the
* specified characters ("0", "9", "A", "a", "…", "_" and "-").
*
- * @returns Initialized ```State``` object with assigned ```State.child``` chain.
+ * @returns Initialized ``State`` object with assigned ``State.child`` chain.
*
- * @throws ```FormatError``` if ```formatString``` does not conform to the method requirements.
+ * @throws ``FormatError`` if `formatString` does not conform to the method requirements.
*/
@Throws(FormatError::class)
fun compile(formatString: String): State {
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/FormatSanitizer.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/FormatSanitizer.kt
index 7c2b45e..74e830d 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/FormatSanitizer.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/FormatSanitizer.kt
@@ -5,28 +5,28 @@ import java.util.*
/**
* ### FormatSanitizer
*
- * Sanitizes given ```formatString``` before it's compilation.
+ * Sanitizes given `formatString` before it's compilation.
*
- * @complexity ```O(2*floor(log(n)))```, and switches to ```O(n^2)``` for ```n < 20``` where
- * ```n = formatString.characters.count```
+ * @complexity `O(2*floor(log(n)))`, and switches to `O(n^2)` for `n < 20` where
+ * `n = formatString.characters.count`
*
- * @requires Format string to contain only flat groups of symbols in ```[]``` and ```{}``` brackets
- * without nested brackets, like ```[[000]99]```. Square bracket ```[]``` groups may contain mixed
+ * @requires Format string to contain only flat groups of symbols in `[]` and `{}` brackets
+ * without nested brackets, like `[[000]99]`. Square bracket `[]` groups may contain mixed
* types of symbols ("0" and "9" with "A" and "a" or "_" and "-"), which sanitizer will divide into
- * separate groups. Such that, ```[0000Aa]``` group will be divided in two groups: ```[0000]```
- * and ```[Aa]```.
+ * separate groups. Such that, `[0000Aa]` group will be divided in two groups: `[0000]`
+ * and `[Aa]`.
*
- * ```FormatSanitizer``` is used by ```Compiler``` before format string compilation.
+ * ``FormatSanitizer`` is used by ``Compiler`` before format string compilation.
*
* @author taflanidi
*/
class FormatSanitizer {
/**
- * Sanitize ```formatString``` before compilation.
+ * Sanitize `formatString` before compilation.
*
* In order to do so, sanitizer splits the string into groups of regular symbols, symbols in square
- * brackets [] and symbols in curly brackets {}. Then, characters in square brackets are sorted in
+ * brackets `[]` and symbols in curly brackets `{}`. Then, characters in square brackets are sorted in
* a way that mandatory symbols go before optional symbols. For instance,
*
* ```
@@ -39,22 +39,22 @@ class FormatSanitizer {
* a ([0099]) b
* ```
*
- * Also, ellipsis in square brackets [] is always placed at the end.
+ * Also, ellipsis in square brackets `[]` is always placed at the end.
*
- * @complexity ```O(2*floor(log(n)))```, and switches to ```O(n^2)``` for ```n < 20``` where
- * ```n = formatString.characters.count```
+ * @complexity `O(2*floor(log(n)))`, and switches to `O(n^2)` for `n < 20` where
+ * `n = formatString.characters.count`
*
- * @requires Format string to contain only flat groups of symbols in ```[]``` and ```{}``` brackets
- * without nested brackets, like ```[[000]99]```. Square bracket ```[]``` groups may contain mixed
+ * @requires Format string to contain only flat groups of symbols in `[]` and `{}` brackets
+ * without nested brackets, like `[[000]99]`. Square bracket `[]` groups may contain mixed
* types of symbols ("0" and "9" with "A" and "a" or "_" and "-"), which sanitizer will divide into
- * separate groups. Such that, ```[0000Aa]``` group will be divided in two groups: ```[0000]```
- * and ```[Aa]```.
+ * separate groups. Such that, `[0000Aa]` group will be divided in two groups: `[0000]`
+ * and `[Aa]`.
*
* @param formatString: mask format string.
*
* @returns Sanitized format string.
*
- * @throws ```FormatError``` if ```formatString``` does not conform to the method requirements.
+ * @throws ``FormatError`` if `formatString` does not conform to the method requirements.
*/
@Throws(Compiler.FormatError::class)
fun sanitize(formatString: String): String {
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Mask.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Mask.kt
index 3c58434..ddc7242 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Mask.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/Mask.kt
@@ -13,10 +13,10 @@ import java.util.*
* Iterates over user input. Creates formatted strings from it. Extracts value specified by mask
* format.
*
- * Provided mask format string is translated by the ```Compiler``` class into a set of states, which
+ * Provided mask format string is translated by the ``Compiler`` class into a set of states, which
* define the formatting and value extraction.
*
- * @see ```Compiler```, ```State``` and ```CaretString``` classes.
+ * @see ``Compiler``, ``State`` and ``CaretString`` classes.
*
* @author taflanidi
*/
@@ -48,14 +48,19 @@ open class Mask(format: String, protected val customNotations: List) {
/**
* User input is complete.
*/
- val complete: Boolean
+ val complete: Boolean,
+ /**
+ Placeholder for remaining text.
+ */
+ val tailPlaceholder: String
) {
fun reversed() =
Result(
this.formattedText.reversed(),
this.extractedValue.reversed(),
this.affinity,
- this.complete
+ this.complete,
+ this.tailPlaceholder.reversed()
)
}
@@ -65,11 +70,11 @@ open class Mask(format: String, protected val customNotations: List) {
/**
* Factory constructor.
*
- * Operates over own ```Mask``` cache where initialized ```Mask``` objects are stored under
+ * Operates over own ``Mask`` cache where initialized ``Mask`` objects are stored under
* corresponding format key:
- * ```[format : mask]```
+ * `[format : mask]`
*
- * @returns Previously cached ```Mask``` object for requested format string. If such it
+ * @returns Previously cached ``Mask`` object for requested format string. If such it
* doesn't exist in cache, the object is constructed, cached and returned.
*/
fun getOrCreate(format: String, customNotations: List): Mask {
@@ -85,10 +90,10 @@ open class Mask(format: String, protected val customNotations: List) {
* Check your mask format is valid.
*
* @param format mask format.
- * @param customNotations a list of custom rules to compile square bracket ```[]``` groups of format symbols.
+ * @param customNotations a list of custom rules to compile square bracket `[]` groups of format symbols.
*
- * @returns ```true``` if this format coupled with custom notations will compile into a working ```Mask``` object.
- * Otherwise ```false```.
+ * @returns `true` if this format coupled with custom notations will compile into a working ``Mask`` object.
+ * Otherwise `false`.
*/
fun isValid(format: String, customNotations: List): Boolean {
return try {
@@ -163,6 +168,9 @@ open class Mask(format: String, protected val customNotations: List) {
}
}
+ var tailState = state
+ var tail = ""
+
while (text.caretGravity.autoskip && !autocompletionStack.empty()) {
val skip: Next = autocompletionStack.pop()
if (modifiedString.length == modifiedCaretPosition) {
@@ -178,8 +186,12 @@ open class Mask(format: String, protected val customNotations: List) {
modifiedCaretPosition -= 1
}
}
+ tailState = skip.state
+ tail = if (skip.insert != null) skip.insert.toString() else tail
}
+ val tailPlaceholder = appendPlaceholder(tailState, tail)
+
return Result(
CaretString(
modifiedString,
@@ -188,7 +200,8 @@ open class Mask(format: String, protected val customNotations: List) {
),
extractedValue,
affinity,
- this.noMandatoryCharactersLeftAfterState(state)
+ this.noMandatoryCharactersLeftAfterState(state),
+ tailPlaceholder
)
}
@@ -352,10 +365,10 @@ open class Mask(format: String, protected val customNotations: List) {
* While scanning through the input string in the `.apply(…)` method, the mask builds a graph of
* autocompletion steps.
*
- * This graph accumulates the results of `.autocomplete()` calls for each consecutive `State`,
- * acting as a `stack` of `Next` object instances.
+ * This graph accumulates the results of `.autocomplete()` calls for each consecutive ``State``,
+ * acting as a `stack` of ``Next`` object instances.
*
- * Each time the `State` returns `null` for its `.autocomplete()`, the graph resets empty.
+ * Each time the ``State`` returns `null` for its `.autocomplete()`, the graph resets empty.
*/
private class AutocompletionStack : Stack() {
override fun push(item: Next?): Next? {
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/RTLMask.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/RTLMask.kt
index 16c2b49..b8ed0f2 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/RTLMask.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/helper/RTLMask.kt
@@ -7,7 +7,7 @@ import java.util.HashMap
/**
* ### RTLMask
*
- * A right-to-left ```Mask``` subclass. Applies format from the string end.
+ * A right-to-left ``Mask`` subclass. Applies format from the string end.
*/
class RTLMask(format: String, customNotations: List) : Mask(reversedFormat(format), customNotations) {
companion object Factory {
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Country.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Country.kt
new file mode 100644
index 0000000..efe8ae3
--- /dev/null
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Country.kt
@@ -0,0 +1,797 @@
+package com.redmadrobot.inputmask.model
+
+/**
+ * ### Country
+ *
+ * Model object representing a **Country** record operated by the ``PhoneInputListener``.
+ */
+data class Country(
+ /**
+ * International country name.
+ */
+ val name: String,
+
+ /**
+ * Country name in its own language.
+ */
+ val nameNative: String?,
+
+ /**
+ * Country emoji.
+ */
+ val emoji: String,
+
+ /**
+ * Country ISO-3166 code, 2 valters.
+ */
+ val iso3166alpha2: String,
+
+ /**
+ * Country ISO-3166 code, 3 valters.
+ */
+ val iso3166alpha3: String,
+
+ /**
+ * Country dial code.
+ */
+ val countryCode: String,
+
+ /**
+ * Primary ``Mask`` format for the country phone numbers.
+ */
+ val primaryFormat: String,
+
+ /**
+ * Affine ``Mask`` formats for the country phone numbers.
+ */
+ val affineFormats: List,
+
+ /**
+ * A regular expression to detect whether or not the entered digits correspond to this particular country.
+ */
+ val phoneRegex: String,
+) {
+ fun phoneStartsWith(digits: String): Boolean = phoneRegex.toRegex().containsMatchIn(digits)
+
+ companion object {
+ fun findCountries(customCountries: List?, includingTerms: List?, excludingTerms: List?, phone: String): List {
+ val includingTermsLowercased = includingTerms?.map { it.lowercase() } ?: listOf()
+ val excludingTermsLowercased = excludingTerms?.map { it.lowercase() } ?: listOf()
+ val phoneDigits = phone.filter(Char::isDigit)
+
+ return (customCountries ?: all).filter {
+ var include: Boolean = false
+
+ if (includingTerms != null) {
+ include = include
+ || includingTermsLowercased.contains(it.name.lowercase())
+ || includingTermsLowercased.contains(it.iso3166alpha2.lowercase())
+ || includingTermsLowercased.contains(it.iso3166alpha3.lowercase())
+ || includingTermsLowercased.contains(it.emoji)
+
+ include = include || if (it.nameNative != null) includingTermsLowercased.contains(it.nameNative) else false
+ } else {
+ include = true
+ }
+
+ var exclude: Boolean = false
+
+ if (excludingTerms != null) {
+ exclude = exclude
+ || excludingTermsLowercased.contains(it.name.lowercase())
+ || excludingTermsLowercased.contains(it.iso3166alpha2.lowercase())
+ || excludingTermsLowercased.contains(it.iso3166alpha3.lowercase())
+ || excludingTermsLowercased.contains(it.emoji)
+
+ exclude = exclude || if (it.nameNative != null) excludingTermsLowercased.contains(it.nameNative) else false
+ }
+
+ include = include && it.phoneStartsWith(phoneDigits)
+
+ include && !exclude
+ }
+ }
+
+ /**
+ A ``Country`` dictionary.
+
+ Feel free to append/correct & file PRs, see https://countrycode.org
+ */
+ val all: List = listOf(
+ Country(
+ "Canada",
+ "Canada",
+ "🇨🇦",
+ "CA",
+ "CAN",
+ "1",
+ "+{1} [000] [000]-[0000]",
+ listOf(),
+ "^1$|^1[2-9]$|^1[2-9][0-8]$|^1204|^1226|^1236|^1249|^1250|^1289|^1306|^1343|^1365|^1367|^1368|^1403|^1416|^1418|^1431|^1437|^1438|^1450|^1474|^1506|^1514|^1519|^1548|^1579|^1581|^1584|^1587|^1604|^1613|^1639|^1647|^1672|^1705|^1709|^1778|^1780|^1782|^1807|^1819|^1825|^1867|^1873|^1902|^1905"
+ ),
+ Country(
+ "USA",
+ "USA",
+ "🇺🇸",
+ "US",
+ "USA",
+ "1",
+ "+{1} [000] [000]-[0000]",
+ listOf(),
+ "^1$|^1[2-9]$|^1[2-9][0-8]$|^1201|^1202|^1203|^1205|^1206|^1207|^1208|^1209|^1209|^1210|^1212|^1213|^1214|^1215|^1216|^1217|^1218|^1219|^1224|^1225|^1227|^1228|^1229|^1231|^1234|^1239|^1240|^1248|^1251|^1252|^1253|^1254|^1256|^1260|^1262|^1267|^1269|^1270|^1274|^1276|^1278|^1281|^1283|^1301|^1302|^1303|^1304|^1305|^1307|^1308|^1309|^1310|^1312|^1313|^1314|^1315|^1316|^1317|^1318|^1319|^1320|^1321|^1323|^1325|^1330|^1331|^1334|^1336|^1337|^1339|^1341|^1347|^1351|^1352|^1360|^1361|^1364|^1369|^1380|^1385|^1386|^1401|^1402|^1404|^1405|^1406|^1407|^1408|^1409|^1410|^1412|^1413|^1414|^1415|^1417|^1419|^1423|^1424|^1425|^1430|^1432|^1434|^1435|^1440|^1442|^1443|^1445|^1447|^1458|^1464|^1469|^1470|^1475|^1478|^1479|^1480|^1484|^1501|^1502|^1503|^1504|^1505|^1507|^1508|^1509|^1510|^1512|^1513|^1515|^1516|^1517|^1518|^1520|^1530|^1531|^1534|^1540|^1541|^1551|^1557|^1559|^1561|^1562|^1563|^1564|^1567|^1570|^1571|^1573|^1574|^1575|^1580|^1585|^1586|^1601|^1602|^1603|^1605|^1606|^1607|^1608|^1609|^1610|^1612|^1614|^1615|^1616|^1617|^1618|^1619|^1620|^1623|^1626|^1627|^1628|^1630|^1631|^1636|^1641|^1646|^1650|^1651|^1657|^1659|^1660|^1661|^1662|^1667|^1669|^1678|^1679|^1681|^1682|^1689|^1701|^1702|^1703|^1704|^1706|^1707|^1708|^1712|^1713|^1714|^1715|^1716|^1717|^1718|^1719|^1720|^1724|^1727|^1730|^1731|^1732|^1734|^1737|^1740|^1747|^1752|^1754|^1757|^1760|^1762|^1763|^1764|^1765|^1769|^1770|^1772|^1773|^1774|^1775|^1779|^1781|^1785|^1786|^1801|^1802|^1803|^1804|^1805|^1806|^1808|^1810|^1812|^1813|^1814|^1815|^1816|^1817|^1818|^1828|^1830|^1831|^1832|^1835|^1843|^1845|^1847|^1848|^1850|^1856|^1857|^1858|^1859|^1860|^1862|^1863|^1864|^1865|^1870|^1872|^1878|^1901|^1903|^1904|^1906|^1907|^1908|^1909|^1910|^1912|^1913|^1914|^1915|^1916|^1917|^1918|^1919|^1920|^1925|^1927|^1928|^1931|^1935|^1936|^1937|^1938|^1940|^1941|^1947|^1949|^1951|^1952|^1954|^1956|^1957|^1959|^1970|^1971|^1972|^1973|^1975|^1978|^1979|^1980|^1984|^1985|^1989"
+ ),
+ Country(
+ "Kazakhstan",
+ "Қазақстан",
+ "🇰🇿",
+ "KZ",
+ "KAZ",
+ "7",
+ "+{7} ([000]) [000]-[00]-[00]",
+ listOf(),
+ "^7$|^7[125670]"
+ ),
+ Country(
+ "Russian Federation",
+ "Российская Федерация",
+ "🇷🇺",
+ "RU",
+ "RUS",
+ "7",
+ "+{7} ([000]) [000]-[00]-[00]",
+ listOf(),
+ "^7$|^7[3489]"
+ ),
+ Country(
+ "Egypt",
+ "مصر",
+ "🇪🇬",
+ "EG",
+ "EGY",
+ "20",
+ "+{20}-[90]-[000]-[0000]",
+ listOf(
+ // TODO
+ ),
+ "^2$|^20$|^20[1-9]"
+ ),
+ Country(
+ "Greece",
+ "Ελλάδα",
+ "🇬🇷",
+ "GR",
+ "GRC",
+ "30",
+ "+{30} [9000] [000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^30"
+ ),
+ Country(
+ "Netherlands",
+ "Nederland",
+ "🇳🇱",
+ "NL",
+ "NLD",
+ "31",
+ "+{31} [9000] [000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^31"
+ ),
+ Country(
+ "Belgium",
+ "Koninkrijk België",
+ "🇧🇪",
+ "BE",
+ "BEL",
+ "32",
+ "+{32} [990] [900] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^32"
+ ),
+ Country(
+ "France",
+ "France",
+ "🇫🇷",
+ "FR",
+ "FRA",
+ "33",
+ "+{33} [0] [00] [00] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^33"
+ ),
+ Country(
+ "Spain",
+ "España",
+ "🇪🇸",
+ "ES",
+ "ESP",
+ "34",
+ "+{34} [000] [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^34"
+ ),
+ Country(
+ "Hungary",
+ "Magyarország",
+ "🇭🇺",
+ "HU",
+ "HUN",
+ "36",
+ "+{36} [90] [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^36"
+ ),
+ Country(
+ "Italy",
+ "Italia",
+ "🇮🇹",
+ "IT",
+ "ITA",
+ "39",
+ "+{39} [990] [000000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^39"
+ ),
+ Country(
+ "Romania",
+ "România",
+ "🇷🇴",
+ "RO",
+ "ROU",
+ "40",
+ "+{40} [900] [900] [000]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^40"
+ ),
+ Country(
+ "Switzerland",
+ "Schweezerland",
+ "🇨🇭",
+ "CH",
+ "CHE",
+ "41",
+ "+{41} {0}[00] [000] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^41"
+ ),
+ Country(
+ "Austria",
+ "Ausztria",
+ "🇦🇹",
+ "AT",
+ "AUT",
+ "43",
+ "+{43} [990] [000] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^43"
+ ),
+ Country(
+ "United Kingdom",
+ "United Kingdom",
+ "🇬🇧",
+ "GB",
+ "GBR",
+ "44",
+ "+{44} ([000]) [0000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^44"
+ ),
+ Country(
+ "Denmark",
+ "Danmark",
+ "🇩🇰",
+ "DK",
+ "DNK",
+ "45",
+ "+{45} [00] [00] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^45"
+ ),
+ Country(
+ "Sweden",
+ "Sverige",
+ "🇸🇪",
+ "SE",
+ "SWE",
+ "46",
+ "+{46} [000] [000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^46"
+ ),
+ Country(
+ "Norway",
+ "Noorweegen",
+ "🇳🇴",
+ "NO",
+ "NOR",
+ "47",
+ "+{47} [00] [00] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^47"
+ ),
+ Country(
+ "Poland",
+ "Polska",
+ "🇵🇱",
+ "PL",
+ "POL",
+ "48",
+ "+{48} [00] [000] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^48"
+ ),
+ Country(
+ "Germany",
+ "Deutschland",
+ "🇩🇪",
+ "DE",
+ "DEU",
+ "49",
+ "+{49} [99900] [9900] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^4$|^49"
+ ),
+ Country(
+ "Peru",
+ "Perú",
+ "🇵🇪",
+ "PE",
+ "PER",
+ "51",
+ "+{51} [000] [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^51"
+ ),
+ Country(
+ "Mexico",
+ "México",
+ "🇲🇽",
+ "MX",
+ "MEX",
+ "52",
+ "+{52} [0000000000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^52"
+ ),
+ Country(
+ "Cuba",
+ "Cuba",
+ "🇨🇺",
+ "CU",
+ "CUB",
+ "53",
+ "+{53} [00] [000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^53"
+ ),
+ Country(
+ "Argentina",
+ "Argentina",
+ "🇦🇷",
+ "AR",
+ "ARG",
+ "54",
+ "+{54} [000] [000]–[0000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^54"
+ ),
+ Country(
+ "Brazil",
+ "Brasil",
+ "🇧🇷",
+ "BR",
+ "BRA",
+ "55",
+ "+{55} [00] [0000]-[0000]",
+ listOf(
+ "+{55} [00] 9[0000]-[0000]", // TODO
+ ),
+ "^5$|^55"
+ ),
+ Country(
+ "Chile",
+ "Chile",
+ "🇨🇱",
+ "CL",
+ "CHL",
+ "56",
+ "+{56} ([000]) [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^56"
+ ),
+ Country(
+ "Colombia",
+ "Colombia",
+ "🇨🇴",
+ "CO",
+ "COL",
+ "57",
+ "+{57}-[000]-[0000000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^57"
+ ),
+ Country(
+ "Venezuela",
+ "Venezuela",
+ "🇻🇪",
+ "VE",
+ "VEN",
+ "58",
+ "+{58} [000] [0000000]",
+ listOf(
+ // TODO
+ ),
+ "^5$|^58"
+ ),
+ Country(
+ "Malaysia",
+ null,
+ "🇲🇾",
+ "MY",
+ "MYS",
+ "60",
+ "+{60} [990] [9000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^60"
+ ),
+ Country(
+ "Australia",
+ "Australia",
+ "🇦🇺",
+ "AU",
+ "AUS",
+ "61",
+ "+{61} [000] [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^61"
+ ),
+ Country(
+ "Indonesia",
+ "Indonesia",
+ "🇮🇩",
+ "ID",
+ "IDN",
+ "62",
+ "+{62} [9000]-[0000]-[0000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^62"
+ ),
+ Country(
+ "Philippines",
+ "Pilipinas",
+ "🇵🇭",
+ "PH",
+ "PHL",
+ "63",
+ "+{63} [900]-[000]-[0000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^63"
+ ),
+ Country(
+ "New Zealand",
+ "Aotearoa",
+ "🇳🇿",
+ "NZ",
+ "NZL",
+ "64",
+ "+{64} [9000] [000] [9000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^64"
+ ),
+ Country(
+ "Singapore",
+ "Singapura",
+ "🇸🇬",
+ "SG",
+ "SGP",
+ "65",
+ "+{65} [0000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^65"
+ ),
+ Country(
+ "Thailand",
+ "ประเทศไทย",
+ "🇹🇭",
+ "TH",
+ "THA",
+ "66",
+ "+{66} [0000000000]",
+ listOf(
+ // TODO
+ ),
+ "^6$|^66"
+ ),
+ Country(
+ "Japan",
+ "日本",
+ "🇯🇵",
+ "JP",
+ "JPN",
+ "81",
+ "+{81} [9900]-[9900]-[0000]",
+ listOf(
+ // TODO
+ ),
+ "^8$|^81"
+ ),
+ Country(
+ "South Korea",
+ "대한민국",
+ "🇰🇷",
+ "KR",
+ "KOR",
+ "82",
+ "+{82} [00] [0000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^8$|^82"
+ ),
+ Country(
+ "Vietnam",
+ "Việt Nam",
+ "🇻🇳",
+ "VN",
+ "VNM",
+ "84",
+ "+{84} [0000] [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^8$|^84"
+ ),
+ Country(
+ "China",
+ "中国",
+ "🇨🇳",
+ "CN",
+ "CHN",
+ "86",
+ "+{86} [000]-[0000]-[0000]",
+ listOf(
+ // TODO
+ ),
+ "^8$|^86"
+ ),
+ Country(
+ "Türkiye",
+ "Türkiye",
+ "🇹🇷",
+ "TR",
+ "TUR",
+ "90",
+ "+{90} ([000]) [000]-[00]-[00]",
+ listOf(
+ // TODO
+ ),
+ "^9$|^90"
+ ),
+ Country(
+ "India",
+ "Bhārat Gaṇarājya",
+ "🇮🇳",
+ "IN",
+ "IND",
+ "91",
+ "+{91} [000] [0000000]",
+ listOf(
+ // TODO
+ ),
+ "^9$|^91"
+ ),
+ Country(
+ "Pakistan",
+ "پاکِستان",
+ "🇵🇰",
+ "PK",
+ "PAK",
+ "92",
+ "+{92} ([000]) [0000000]",
+ listOf(
+ // TODO
+ ),
+ "^9$|^92"
+ ),
+ Country(
+ "Afghanistan",
+ null,
+ "🇦🇫",
+ "AF",
+ "AFG",
+ "93",
+ "+{93} [00] [0000000]",
+ listOf(
+ // TODO
+ ),
+ "^9$|^93"
+ ),
+ Country(
+ "Sri Lanka",
+ "ශ්රී ලංකා",
+ "🇱🇰",
+ "LK",
+ "LKA",
+ "94",
+ "+{94} [000]-[000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^9$|^94"
+ ),
+ Country(
+ "Greenland",
+ "Kalaallit Nunaat",
+ "🇬🇱",
+ "GL",
+ "GRL",
+ "299",
+ "+{299} [00] [00] [00]",
+ listOf(
+ // TODO
+ ),
+ "^2$|^29$|^299"
+ ),
+ Country(
+ "Portugal",
+ "Portugal",
+ "🇵🇹",
+ "PT",
+ "PRT",
+ "351",
+ "+{351} [000] [000] [9000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^35$|^351"
+ ),
+ Country(
+ "Finland",
+ "Suomi",
+ "🇫🇮",
+ "FI",
+ "FIN",
+ "358",
+ "+{358} [0] [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^35$|^358"
+ ),
+ Country(
+ "Lithuania",
+ "Lietuva",
+ "🇱🇹",
+ "LT",
+ "LTU",
+ "370",
+ "+{370} ([9000]) [900] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^37$|^370"
+ ),
+ Country(
+ "Latvia",
+ "Latvija",
+ "🇱🇻",
+ "LV",
+ "LVA",
+ "371",
+ "+{371} [900] [9900] [900]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^37$|^371"
+ ),
+ Country(
+ "Estonia",
+ "Eesti",
+ "🇪🇪",
+ "EE",
+ "EST",
+ "372",
+ "+{372} [000] [0000]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^37$|^372"
+ ),
+ Country(
+ "Belarus",
+ "Белару́сь",
+ "",
+ "BY",
+ "BLR",
+ "375",
+ "+{375} ([000]) [000]-[00]-[00]",
+ listOf(
+ // TODO
+ ),
+ "^3$|^37$|^375"
+ ),
+ Country(
+ "Ukraine",
+ "Україна",
+ "🇺🇦",
+ "UA",
+ "UKR",
+ "380",
+ "+{380} ([00]) [000]-[00]-[00]",
+ listOf(),
+ "^3$|^38$|^380"
+ ),
+ Country(
+ "Georgia",
+ "საქართველო",
+ "🇬🇪",
+ "GE",
+ "GEO",
+ "995",
+ "+{995} ([000]) [000] [000]",
+ listOf(
+ // TODO
+ ),
+ "^9$|^99$|^995"
+ ),
+ )
+
+ }
+
+}
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Next.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Next.kt
index 4971101..048fc8e 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Next.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/Next.kt
@@ -4,7 +4,7 @@ package com.redmadrobot.inputmask.model
* ### Next
*
* Model object that represents a set of actions that should take place when transition from one
- * ```State``` to another occurs.
+ * ``State`` to another occurs.
*
* @author taflanidi
*/
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/State.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/State.kt
index e3dfbed..50a1724 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/State.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/State.kt
@@ -18,7 +18,7 @@ abstract class State(val child: State?) {
*
* @param character character from the user input string.
*
- * @returns ```Next``` object instance with a set of actions that should take place when the user
+ * @returns ``Next`` object instance with a set of actions that should take place when the user
* input character is accepted.
*
* @throws Fatal error, if the method is not implemented.
@@ -28,8 +28,8 @@ abstract class State(val child: State?) {
/**
* Automatically complete user input.
*
- * @returns ```Next``` object instance with a set of actions to complete user input. If no
- * autocomplete available, returns ```nil```.
+ * @returns ``Next`` object instance with a set of actions to complete user input. If no
+ * autocomplete available, returns `null`.
*/
open fun autocomplete(): Next? {
return null
@@ -38,10 +38,10 @@ abstract class State(val child: State?) {
/**
* Obtain the next state.
*
- * Sometimes it is necessary to override this behavior. For instance, ```State``` may want to
- * return ```self``` as the next state under certain conditions.
+ * Sometimes it is necessary to override this behavior. For instance, ``State`` may want to
+ * return ``self`` as the next state under certain conditions.
*
- * @returns ```State``` object.
+ * @returns ``State`` object.
*/
open fun nextState(): State {
return this.child!!
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/EOLState.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/EOLState.kt
index cc4d667..24f8b6b 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/EOLState.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/EOLState.kt
@@ -8,7 +8,7 @@ import com.redmadrobot.inputmask.model.State
*
* End-of-line state. Serves as mask format terminator character.
*
- * Does not accept any character. Always returns ```self``` as the next state, ignoring the child
+ * Does not accept any character. Always returns `self` as the next state, ignoring the child
* state given during initialization.
*
* @author taflanidi
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FixedState.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FixedState.kt
index 84a6a7a..e5a84a6 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FixedState.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FixedState.kt
@@ -6,7 +6,7 @@ import com.redmadrobot.inputmask.model.State
/**
* ### FixedState
*
- * Represents characters in curly braces {}.
+ * Represents characters in curly braces `{}`.
*
* Accepts every character but does not put it into the result string, unless the character equals
* the one from the mask format. If it's not, inserts the symbol from the mask format into the
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FreeState.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FreeState.kt
index 1bf61b9..8c0a12b 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FreeState.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/FreeState.kt
@@ -12,7 +12,7 @@ import com.redmadrobot.inputmask.model.State
* the one from the mask format. If it's not, inserts the symbol from the mask format into the
* result.
*
- * Always returns ```nil``` as an extracted value, does not affect the resulting value.
+ * Always returns `null` as an extracted value, does not affect the resulting value.
*
* @author taflanidi
*/
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/OptionalValueState.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/OptionalValueState.kt
index cdff87e..85ffa86 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/OptionalValueState.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/OptionalValueState.kt
@@ -6,14 +6,14 @@ import com.redmadrobot.inputmask.model.State
/**
* ### OptionalValueState
*
- * Represents optional characters in square brackets [].
+ * Represents optional characters in square brackets `[]`.
*
* Accepts any characters, but puts into the result string only the characters of own type
- * (see ```StateType```).
+ * (see ``StateType``).
*
* Returns accepted characters of own type as an extracted value.
*
- * @see ```OptionalValueState.StateType```
+ * @see ``OptionalValueState.StateType``
*
* @author taflanidi
*/
diff --git a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/ValueState.kt b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/ValueState.kt
index de698f2..42326bf 100644
--- a/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/ValueState.kt
+++ b/inputmask/src/main/kotlin/com/redmadrobot/inputmask/model/state/ValueState.kt
@@ -6,14 +6,14 @@ import com.redmadrobot.inputmask.model.State
/**
* ### ValueState
*
- * Represents mandatory characters in square brackets [].
+ * Represents mandatory characters in square brackets `[]`.
*
- * Accepts only characters of own type (see ```StateType```). Puts accepted characters into the
+ * Accepts only characters of own type (see ``StateType``). Puts accepted characters into the
* result string.
*
* Returns accepted characters as an extracted value.
*
- * @see ```ValueState.StateType```
+ * @see ``ValueState.StateType``
*
* @author taflanidi
*/
@@ -22,10 +22,10 @@ class ValueState : State {
/**
* ### StateType
*
- * ```Numeric``` stands for [9] characters
- * ```Literal``` stands for [a] characters
- * ```AlphaNumeric``` stands for [-] characters
- * ```Ellipsis``` stands for […] characters
+ * `Numeric` stands for `[9]` characters
+ * `Literal` stands for `[a]` characters
+ * `AlphaNumeric` stands for `[-]` characters
+ * `Ellipsis` stands for `[…]` characters
*/
sealed class StateType {
class Numeric : StateType()
@@ -38,7 +38,7 @@ class ValueState : State {
val type: StateType
/**
- * Constructor for elliptical ```ValueState```
+ * Constructor for elliptical ``ValueState``
*/
constructor(inheritedType: StateType) : super(null) {
this.type = StateType.Ellipsis(inheritedType)
diff --git a/settings.gradle b/settings.gradle
index de0e53f..aaec5cc 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1,18 @@
-include ':app', ':inputmask'
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven { url 'https://jitpack.io' }
+ }
+}
+rootProject.name = "input-mask-android"
+include ':app'
+include ':inputmask'
diff --git a/version.properties b/version.properties
deleted file mode 100644
index 89f1804..0000000
--- a/version.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file should be checked into Version Control Systems,
-# as it contains default parameters to version configuration.
-version_code=9
-version_name=6.0.0