From af2d4bae8616b9747098b27e88a43cf121327e5a Mon Sep 17 00:00:00 2001 From: dmitriy Date: Tue, 23 Apr 2019 17:31:57 +0300 Subject: [PATCH 1/5] migrated to AndroidX updated targetSdk to 28, minSDK to 16 --- app/build.gradle | 24 ++++++++---- .../pinlockviewapp/SampleActivity.java | 9 +++-- app/src/main/res/layout/activity_sample.xml | 4 +- build.gradle | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- pinlockview/build.gradle | 23 +++++++---- .../andrognito/pinlockview/IndicatorDots.java | 5 ++- .../pinlockview/ItemSpaceDecoration.java | 3 +- .../pinlockview/LTRGridLayoutManager.java | 5 ++- .../pinlockview/PinLockAdapter.java | 39 ++++++++----------- .../andrognito/pinlockview/PinLockView.java | 5 ++- .../andrognito/pinlockview/ResourceUtils.java | 9 +++-- 12 files changed, 76 insertions(+), 58 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index de9556a1..cde56bc8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,13 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 28 defaultConfig { applicationId "com.andrognito.pinlockviewapp" - minSdkVersion 11 - targetSdkVersion 25 + minSdkVersion 16 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -19,9 +18,18 @@ android { } } +allprojects { + gradle.projectsEvaluated { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:deprecation" + } + } +} + dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:25.3.1' - compile project(':pinlockview') + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':pinlockview') + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.0.0' + testImplementation 'junit:junit:4.12' } diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java index f6414d5a..b02a7aeb 100644 --- a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java +++ b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java @@ -1,12 +1,13 @@ package com.andrognito.pinlockviewapp; import android.os.Bundle; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Window; import android.view.WindowManager; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; + import com.andrognito.pinlockview.IndicatorDots; import com.andrognito.pinlockview.PinLockListener; import com.andrognito.pinlockview.PinLockView; @@ -43,8 +44,8 @@ protected void onCreate(Bundle savedInstanceState) { WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_sample); - mPinLockView = (PinLockView) findViewById(R.id.pin_lock_view); - mIndicatorDots = (IndicatorDots) findViewById(R.id.indicator_dots); + mPinLockView = findViewById(R.id.pin_lock_view); + mIndicatorDots = findViewById(R.id.indicator_dots); mPinLockView.attachIndicatorDots(mIndicatorDots); mPinLockView.setPinLockListener(mPinLockListener); diff --git a/app/src/main/res/layout/activity_sample.xml b/app/src/main/res/layout/activity_sample.xml index 05b65c72..da0fa603 100644 --- a/app/src/main/res/layout/activity_sample.xml +++ b/app/src/main/res/layout/activity_sample.xml @@ -7,7 +7,7 @@ android:background="@color/mine_shaft" tools:context="com.andrognito.pinlockviewapp.SampleActivity"> - - 0) { mDeleteButton.setOnClickListener(new View.OnClickListener() { @@ -249,14 +254,4 @@ public boolean onTouch(View v, MotionEvent event) { } } } - - public interface OnNumberClickListener { - void onNumberClicked(int keyValue); - } - - public interface OnDeleteClickListener { - void onDeleteClicked(); - - void onDeleteLongClicked(); - } } diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java index 72eade71..28fbcdb3 100644 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java @@ -3,10 +3,11 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + /** * Represents a numeric lock view which can used to taken numbers as input. * The length of the input can be customized using {@link PinLockView#setPinLength(int)}, the default value being 4 diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java b/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java index 57d7016b..f75f301c 100644 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java @@ -2,10 +2,11 @@ import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorRes; -import android.support.annotation.DimenRes; -import android.support.annotation.DrawableRes; -import android.support.v4.content.ContextCompat; + +import androidx.annotation.ColorRes; +import androidx.annotation.DimenRes; +import androidx.annotation.DrawableRes; +import androidx.core.content.ContextCompat; /** * Created by aritraroy on 10/06/16. From 387899f27f17f369394f69d0776e71685862ba87 Mon Sep 17 00:00:00 2001 From: dmitriy Date: Tue, 23 Apr 2019 19:41:53 +0300 Subject: [PATCH 2/5] added animation in sample demo on error pin added red error pins --- .../pinlockviewapp/SampleActivity.java | 17 +++++++- .../andrognito/pinlockview/IndicatorDots.java | 42 ++++++++++++++----- pinlockview/src/main/res/anim/cycles_7.xml | 3 ++ pinlockview/src/main/res/anim/shake_wrong.xml | 6 +++ .../src/main/res/drawable/dot_error.xml | 5 +++ pinlockview/src/main/res/values/colors.xml | 1 + 6 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 pinlockview/src/main/res/anim/cycles_7.xml create mode 100644 pinlockview/src/main/res/anim/shake_wrong.xml create mode 100644 pinlockview/src/main/res/drawable/dot_error.xml diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java index b02a7aeb..bced28f2 100644 --- a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java +++ b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java @@ -1,9 +1,12 @@ package com.andrognito.pinlockviewapp; import android.os.Bundle; +import android.os.Handler; import android.util.Log; import android.view.Window; import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; @@ -23,6 +26,16 @@ public class SampleActivity extends AppCompatActivity { @Override public void onComplete(String pin) { Log.d(TAG, "Pin complete: " + pin); + Animation shake = AnimationUtils.loadAnimation(SampleActivity.this, R.anim.shake_wrong); + mIndicatorDots.startAnimation(shake); + mIndicatorDots.setErrorDots(); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + mIndicatorDots.setDefaultDots(); + mPinLockView.resetPinLockView(); + } + }, 1000); } @Override @@ -47,6 +60,7 @@ protected void onCreate(Bundle savedInstanceState) { mPinLockView = findViewById(R.id.pin_lock_view); mIndicatorDots = findViewById(R.id.indicator_dots); + mPinLockView.attachIndicatorDots(mIndicatorDots); mPinLockView.setPinLockListener(mPinLockListener); //mPinLockView.setCustomKeySet(new int[]{2, 3, 1, 5, 9, 6, 7, 0, 8, 4}); @@ -55,6 +69,7 @@ protected void onCreate(Bundle savedInstanceState) { mPinLockView.setPinLength(4); mPinLockView.setTextColor(ContextCompat.getColor(this, R.color.white)); - mIndicatorDots.setIndicatorType(IndicatorDots.IndicatorType.FILL_WITH_ANIMATION); + mIndicatorDots.setIndicatorType(IndicatorDots.IndicatorType.FIXED); + mIndicatorDots.getPinLength(); } } diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java index 0007dd00..cf70dcc1 100644 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java @@ -22,23 +22,14 @@ */ public class IndicatorDots extends LinearLayout { - @IntDef({IndicatorType.FIXED, IndicatorType.FILL, IndicatorType.FILL_WITH_ANIMATION}) - @Retention(RetentionPolicy.SOURCE) - public @interface IndicatorType { - int FIXED = 0; - int FILL = 1; - int FILL_WITH_ANIMATION = 2; - } - private static final int DEFAULT_PIN_LENGTH = 4; - private int mDotDiameter; private int mDotSpacing; private int mFillDrawable; private int mEmptyDrawable; + private int mErrorDrawable; private int mPinLength; private int mIndicatorType; - private int mPreviousLength; public IndicatorDots(Context context) { @@ -59,6 +50,8 @@ public IndicatorDots(Context context, AttributeSet attrs, int defStyleAttr) { mDotSpacing = (int) typedArray.getDimension(R.styleable.PinLockView_dotSpacing, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_dot_spacing)); mFillDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, R.drawable.dot_filled); + mErrorDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, + R.drawable.dot_error); mEmptyDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotEmptyBackground, R.drawable.dot_empty); mPinLength = typedArray.getInt(R.styleable.PinLockView_pinLength, DEFAULT_PIN_LENGTH); @@ -141,6 +134,23 @@ void updateDot(int length) { } } + public void setErrorDots() { + for (int i = 0; i < getChildCount(); i++) { + View v = getChildAt(i); + errorDot(v); + } + } + + public void setDefaultDots() { +// for (int i = 0; i < getChildCount(); i++) { +// View v = getChildAt(i); +// emptyDot(v); +// } + removeAllViews(); + initView(getContext()); + mPreviousLength = 0; + } + private void emptyDot(View dot) { dot.setBackgroundResource(mEmptyDrawable); } @@ -149,6 +159,10 @@ private void fillDot(View dot) { dot.setBackgroundResource(mFillDrawable); } + private void errorDot(View dot) { + dot.setBackgroundResource(mErrorDrawable); + } + public int getPinLength() { return mPinLength; } @@ -170,4 +184,12 @@ public void setIndicatorType(@IndicatorType int type) { removeAllViews(); initView(getContext()); } + + @IntDef({IndicatorType.FIXED, IndicatorType.FILL, IndicatorType.FILL_WITH_ANIMATION}) + @Retention(RetentionPolicy.SOURCE) + public @interface IndicatorType { + int FIXED = 0; + int FILL = 1; + int FILL_WITH_ANIMATION = 2; + } } diff --git a/pinlockview/src/main/res/anim/cycles_7.xml b/pinlockview/src/main/res/anim/cycles_7.xml new file mode 100644 index 00000000..4bfb143a --- /dev/null +++ b/pinlockview/src/main/res/anim/cycles_7.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/pinlockview/src/main/res/anim/shake_wrong.xml b/pinlockview/src/main/res/anim/shake_wrong.xml new file mode 100644 index 00000000..26f89129 --- /dev/null +++ b/pinlockview/src/main/res/anim/shake_wrong.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/pinlockview/src/main/res/drawable/dot_error.xml b/pinlockview/src/main/res/drawable/dot_error.xml new file mode 100644 index 00000000..828f2df7 --- /dev/null +++ b/pinlockview/src/main/res/drawable/dot_error.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/pinlockview/src/main/res/values/colors.xml b/pinlockview/src/main/res/values/colors.xml index c04e047a..28228652 100644 --- a/pinlockview/src/main/res/values/colors.xml +++ b/pinlockview/src/main/res/values/colors.xml @@ -2,5 +2,6 @@ #fff #aaa8a8 + #9E0000 #303030 \ No newline at end of file From 0472476855b5fc84e6d5804e2f31ba8e9dade2df Mon Sep 17 00:00:00 2001 From: padmitriy Date: Wed, 24 Apr 2019 01:07:42 +0300 Subject: [PATCH 3/5] added success dots added second dots line in demo --- .../pinlockviewapp/SampleActivity.java | 21 ++++++++++++------- app/src/main/res/layout/activity_sample.xml | 20 ++++++++++++------ .../andrognito/pinlockview/IndicatorDots.java | 14 +++++++++++++ .../src/main/res/drawable/dot_success.xml | 5 +++++ pinlockview/src/main/res/values/colors.xml | 7 ++++--- 5 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 pinlockview/src/main/res/drawable/dot_success.xml diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java index bced28f2..210b7756 100644 --- a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java +++ b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java @@ -20,20 +20,25 @@ public class SampleActivity extends AppCompatActivity { public static final String TAG = "PinLockView"; private PinLockView mPinLockView; - private IndicatorDots mIndicatorDots; + private IndicatorDots mIndicatorDotsFirst; + private IndicatorDots mIndicatorDotsSecond; private PinLockListener mPinLockListener = new PinLockListener() { @Override public void onComplete(String pin) { Log.d(TAG, "Pin complete: " + pin); Animation shake = AnimationUtils.loadAnimation(SampleActivity.this, R.anim.shake_wrong); - mIndicatorDots.startAnimation(shake); - mIndicatorDots.setErrorDots(); + mIndicatorDotsFirst.startAnimation(shake); +// mIndicatorDotsFirst.setErrorDots(); + mIndicatorDotsFirst.setSuccessDots(); new Handler().postDelayed(new Runnable() { @Override public void run() { - mIndicatorDots.setDefaultDots(); + mIndicatorDotsFirst.setDefaultDots(); mPinLockView.resetPinLockView(); + +// mPinLockView.attachIndicatorDots(mIndicatorDotsSecond); + } }, 1000); } @@ -58,10 +63,11 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_sample); mPinLockView = findViewById(R.id.pin_lock_view); - mIndicatorDots = findViewById(R.id.indicator_dots); + mIndicatorDotsFirst = findViewById(R.id.indicator_dots_first); + mIndicatorDotsSecond = findViewById(R.id.indicator_dots_second); - mPinLockView.attachIndicatorDots(mIndicatorDots); + mPinLockView.attachIndicatorDots(mIndicatorDotsFirst); mPinLockView.setPinLockListener(mPinLockListener); //mPinLockView.setCustomKeySet(new int[]{2, 3, 1, 5, 9, 6, 7, 0, 8, 4}); //mPinLockView.enableLayoutShuffling(); @@ -69,7 +75,6 @@ protected void onCreate(Bundle savedInstanceState) { mPinLockView.setPinLength(4); mPinLockView.setTextColor(ContextCompat.getColor(this, R.color.white)); - mIndicatorDots.setIndicatorType(IndicatorDots.IndicatorType.FIXED); - mIndicatorDots.getPinLength(); + mIndicatorDotsFirst.setIndicatorType(IndicatorDots.IndicatorType.FIXED); } } diff --git a/app/src/main/res/layout/activity_sample.xml b/app/src/main/res/layout/activity_sample.xml index da0fa603..f451c7da 100644 --- a/app/src/main/res/layout/activity_sample.xml +++ b/app/src/main/res/layout/activity_sample.xml @@ -12,7 +12,7 @@ android:layout_width="84dp" android:layout_height="84dp" android:layout_centerHorizontal="true" - android:layout_marginTop="104dp" + android:layout_marginTop="86dp" android:src="@drawable/img_no_avatar" /> + android:layout_marginTop="32dp" /> + + + + + \ No newline at end of file diff --git a/pinlockview/src/main/res/values/colors.xml b/pinlockview/src/main/res/values/colors.xml index 28228652..f9ce4d85 100644 --- a/pinlockview/src/main/res/values/colors.xml +++ b/pinlockview/src/main/res/values/colors.xml @@ -1,7 +1,8 @@ #fff - #aaa8a8 - #9E0000 - #303030 + #9E9C9C + #A50000 + #50BD00 + #333333 \ No newline at end of file From 7c723d906aaaf0cb88911cc8d0aa16a452e1d473 Mon Sep 17 00:00:00 2001 From: dmitriy Date: Wed, 24 Apr 2019 13:51:28 +0300 Subject: [PATCH 4/5] converted to kotlin minor changes --- app/build.gradle | 9 +- .../pinlockviewapp/SampleActivity.java | 80 ---- .../pinlockviewapp/SampleActivity.kt | 96 ++++ build.gradle | 2 + pinlockview/build.gradle | 13 +- .../CustomizationOptionsBundle.java | 88 ---- .../pinlockview/CustomizationOptionsBundle.kt | 21 + .../andrognito/pinlockview/IndicatorDots.java | 209 --------- .../andrognito/pinlockview/IndicatorDots.kt | 195 ++++++++ .../pinlockview/ItemSpaceDecoration.java | 47 -- .../pinlockview/ItemSpaceDecoration.kt | 37 ++ .../pinlockview/LTRGridLayoutManager.java | 32 -- .../pinlockview/LTRGridLayoutManager.kt | 26 ++ .../pinlockview/PinLockAdapter.java | 257 ----------- .../andrognito/pinlockview/PinLockAdapter.kt | 205 +++++++++ ...inLockListener.java => PinLockListener.kt} | 14 +- .../andrognito/pinlockview/PinLockView.java | 433 ------------------ .../com/andrognito/pinlockview/PinLockView.kt | 411 +++++++++++++++++ .../andrognito/pinlockview/ResourceUtils.java | 31 -- .../andrognito/pinlockview/ResourceUtils.kt | 34 ++ .../pinlockview/ShuffleArrayUtils.java | 33 -- .../pinlockview/ShuffleArrayUtils.kt | 33 ++ 22 files changed, 1085 insertions(+), 1221 deletions(-) delete mode 100644 app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java create mode 100644 app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.kt rename pinlockview/src/main/java/com/andrognito/pinlockview/{PinLockListener.java => PinLockListener.kt} (63%) delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.kt delete mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.java create mode 100644 pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.kt diff --git a/app/build.gradle b/app/build.gradle index cde56bc8..d0b0db20 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' android { compileSdkVersion 28 @@ -29,7 +31,12 @@ allprojects { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':pinlockview') - implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.recyclerview:recyclerview:1.0.0' testImplementation 'junit:junit:4.12' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "androidx.core:core-ktx:1.0.1" +} +repositories { + mavenCentral() } diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java deleted file mode 100644 index 210b7756..00000000 --- a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.andrognito.pinlockviewapp; - -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.Window; -import android.view.WindowManager; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; - -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.ContextCompat; - -import com.andrognito.pinlockview.IndicatorDots; -import com.andrognito.pinlockview.PinLockListener; -import com.andrognito.pinlockview.PinLockView; - -public class SampleActivity extends AppCompatActivity { - - public static final String TAG = "PinLockView"; - - private PinLockView mPinLockView; - private IndicatorDots mIndicatorDotsFirst; - private IndicatorDots mIndicatorDotsSecond; - - private PinLockListener mPinLockListener = new PinLockListener() { - @Override - public void onComplete(String pin) { - Log.d(TAG, "Pin complete: " + pin); - Animation shake = AnimationUtils.loadAnimation(SampleActivity.this, R.anim.shake_wrong); - mIndicatorDotsFirst.startAnimation(shake); -// mIndicatorDotsFirst.setErrorDots(); - mIndicatorDotsFirst.setSuccessDots(); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - mIndicatorDotsFirst.setDefaultDots(); - mPinLockView.resetPinLockView(); - -// mPinLockView.attachIndicatorDots(mIndicatorDotsSecond); - - } - }, 1000); - } - - @Override - public void onEmpty() { - Log.d(TAG, "Pin empty"); - } - - @Override - public void onPinChange(int pinLength, String intermediatePin) { - Log.d(TAG, "Pin changed, new length " + pinLength + " with intermediate pin " + intermediatePin); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - setContentView(R.layout.activity_sample); - - mPinLockView = findViewById(R.id.pin_lock_view); - mIndicatorDotsFirst = findViewById(R.id.indicator_dots_first); - mIndicatorDotsSecond = findViewById(R.id.indicator_dots_second); - - - mPinLockView.attachIndicatorDots(mIndicatorDotsFirst); - mPinLockView.setPinLockListener(mPinLockListener); - //mPinLockView.setCustomKeySet(new int[]{2, 3, 1, 5, 9, 6, 7, 0, 8, 4}); - //mPinLockView.enableLayoutShuffling(); - - mPinLockView.setPinLength(4); - mPinLockView.setTextColor(ContextCompat.getColor(this, R.color.white)); - - mIndicatorDotsFirst.setIndicatorType(IndicatorDots.IndicatorType.FIXED); - } -} diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt new file mode 100644 index 00000000..a51f043c --- /dev/null +++ b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt @@ -0,0 +1,96 @@ +package com.andrognito.pinlockviewapp + +import android.os.Bundle +import android.os.Handler +import android.util.Log +import android.view.Window +import android.view.WindowManager +import android.view.animation.AnimationUtils +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import com.andrognito.pinlockview.IndicatorDots +import com.andrognito.pinlockview.PinLockListener +import com.andrognito.pinlockview.PinLockView + +class SampleActivity : AppCompatActivity() { + + private var mPinLockView: PinLockView? = null + private var mIndicatorDotsFirst: IndicatorDots? = null + private var mIndicatorDotsSecond: IndicatorDots? = null + + private val mPinLockFirstListener = object : PinLockListener { + override fun onComplete(pin: String) { + Log.d(TAG, "Pin complete: $pin") + val shake = AnimationUtils.loadAnimation(this@SampleActivity, R.anim.shake_wrong) + mIndicatorDotsFirst!!.startAnimation(shake) + // mIndicatorDotsFirst.setErrorDots(); + mIndicatorDotsFirst!!.setSuccessDots() + Handler().postDelayed({ + mIndicatorDotsFirst!!.setDefaultDots() + mPinLockView!!.resetPinLockView() + + // mPinLockView.attachIndicatorDots(mIndicatorDotsSecond); + }, 1000) + } + + override fun onEmpty() { + Log.d(TAG, "Pin empty") + } + + override fun onPinChange(pinLength: Int, intermediatePin: String) { + Log.d(TAG, "Pin changed, new length $pinLength with intermediate pin $intermediatePin") + } + } + + private val mPinLockSecondListener = object : PinLockListener { + override fun onComplete(pin: String) { + Log.d(TAG, "Pin complete: $pin") + val shake = AnimationUtils.loadAnimation(this@SampleActivity, R.anim.shake_wrong) + mIndicatorDotsFirst!!.startAnimation(shake) + // mIndicatorDotsFirst.setErrorDots(); + mIndicatorDotsFirst!!.setSuccessDots() + Handler().postDelayed({ + mIndicatorDotsFirst!!.setDefaultDots() + mPinLockView!!.resetPinLockView() + + // mPinLockView.attachIndicatorDots(mIndicatorDotsSecond); + }, 1000) + } + + override fun onEmpty() { + Log.d(TAG, "Pin empty") + } + + override fun onPinChange(pinLength: Int, intermediatePin: String) { + Log.d(TAG, "Pin changed, new length $pinLength with intermediate pin $intermediatePin") + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + requestWindowFeature(Window.FEATURE_NO_TITLE) + window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN) + setContentView(R.layout.activity_sample) + + mPinLockView = findViewById(R.id.pin_lock_view) + mIndicatorDotsFirst = findViewById(R.id.indicator_dots_first) + mIndicatorDotsSecond = findViewById(R.id.indicator_dots_second) + + + mPinLockView!!.attachIndicatorDots(mIndicatorDotsFirst!!) + mPinLockView!!.setPinLockListener(mPinLockFirstListener) + //mPinLockView.setCustomKeySet(new int[]{2, 3, 1, 5, 9, 6, 7, 0, 8, 4}); + //mPinLockView.enableLayoutShuffling(); + + mPinLockView!!.pinLength = 4 + mPinLockView!!.textColor = ContextCompat.getColor(this, R.color.white) + + mIndicatorDotsFirst!!.indicatorType = IndicatorDots.IndicatorType.FIXED + } + + companion object { + + val TAG = "PinLockView" + } +} diff --git a/build.gradle b/build.gradle index 81a61543..97d3cd5b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.30' repositories { jcenter() google() @@ -9,6 +10,7 @@ buildscript { classpath 'com.android.tools.build:gradle:3.4.0' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/pinlockview/build.gradle b/pinlockview/build.gradle index a038b7cb..24585419 100644 --- a/pinlockview/build.gradle +++ b/pinlockview/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' ext { bintrayRepo = 'maven' @@ -52,10 +54,15 @@ allprojects { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "androidx.core:core-ktx:1.0.1" testImplementation 'junit:junit:4.12' } -apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' -apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' \ No newline at end of file +//apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' +//apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java b/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java deleted file mode 100644 index 63eee73e..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.andrognito.pinlockview; - -import android.graphics.drawable.Drawable; - -/** - * The customization options for the buttons in {@link PinLockView} - * passed to the {@link PinLockAdapter} to decorate the individual views - * - * Created by aritraroy on 01/06/16. - */ -public class CustomizationOptionsBundle { - - private int textColor; - private int textSize; - private int buttonSize; - private Drawable buttonBackgroundDrawable; - private Drawable deleteButtonDrawable; - private int deleteButtonSize; - private boolean showDeleteButton; - private int deleteButtonPressesColor; - - public CustomizationOptionsBundle() { - } - - public int getTextColor() { - return textColor; - } - - public void setTextColor(int textColor) { - this.textColor = textColor; - } - - public int getTextSize() { - return textSize; - } - - public void setTextSize(int textSize) { - this.textSize = textSize; - } - - public int getButtonSize() { - return buttonSize; - } - - public void setButtonSize(int buttonSize) { - this.buttonSize = buttonSize; - } - - public Drawable getButtonBackgroundDrawable() { - return buttonBackgroundDrawable; - } - - public void setButtonBackgroundDrawable(Drawable buttonBackgroundDrawable) { - this.buttonBackgroundDrawable = buttonBackgroundDrawable; - } - - public Drawable getDeleteButtonDrawable() { - return deleteButtonDrawable; - } - - public void setDeleteButtonDrawable(Drawable deleteButtonDrawable) { - this.deleteButtonDrawable = deleteButtonDrawable; - } - - public int getDeleteButtonSize() { - return deleteButtonSize; - } - - public void setDeleteButtonSize(int deleteButtonSize) { - this.deleteButtonSize = deleteButtonSize; - } - - public boolean isShowDeleteButton() { - return showDeleteButton; - } - - public void setShowDeleteButton(boolean showDeleteButton) { - this.showDeleteButton = showDeleteButton; - } - - public int getDeleteButtonPressesColor() { - return deleteButtonPressesColor; - } - - public void setDeleteButtonPressesColor(int deleteButtonPressesColor) { - this.deleteButtonPressesColor = deleteButtonPressesColor; - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.kt new file mode 100644 index 00000000..4f428938 --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.kt @@ -0,0 +1,21 @@ +package com.andrognito.pinlockview + +import android.graphics.drawable.Drawable + +/** + * The customization options for the buttons in [PinLockView] + * passed to the [PinLockAdapter] to decorate the individual views + * + * Created by aritraroy on 01/06/16. + */ +class CustomizationOptionsBundle { + + var textColor: Int = 0 + var textSize: Int = 0 + var buttonSize: Int = 0 + var buttonBackgroundDrawable: Drawable? = null + var deleteButtonDrawable: Drawable? = null + var deleteButtonSize: Int = 0 + var isShowDeleteButton: Boolean = false + var deleteButtonPressesColor: Int = 0 +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java deleted file mode 100644 index 50f7c15c..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.andrognito.pinlockview; - -import android.animation.LayoutTransition; -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -import androidx.annotation.IntDef; -import androidx.core.view.ViewCompat; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * It represents a set of indicator dots which when attached with {@link PinLockView} - * can be used to indicate the current length of the input - *

- * Created by aritraroy on 01/06/16. - */ -public class IndicatorDots extends LinearLayout { - - private static final int DEFAULT_PIN_LENGTH = 4; - private int mDotDiameter; - private int mDotSpacing; - private int mFillDrawable; - private int mEmptyDrawable; - private int mErrorDrawable; - private int mSuccessDrawable; - private int mPinLength; - private int mIndicatorType; - private int mPreviousLength; - - public IndicatorDots(Context context) { - this(context, null); - } - - public IndicatorDots(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public IndicatorDots(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PinLockView); - - try { - mDotDiameter = (int) typedArray.getDimension(R.styleable.PinLockView_dotDiameter, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_dot_diameter)); - mDotSpacing = (int) typedArray.getDimension(R.styleable.PinLockView_dotSpacing, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_dot_spacing)); - mFillDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, - R.drawable.dot_filled); - mErrorDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, - R.drawable.dot_error); - mSuccessDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, - R.drawable.dot_success); - mEmptyDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotEmptyBackground, - R.drawable.dot_empty); - mPinLength = typedArray.getInt(R.styleable.PinLockView_pinLength, DEFAULT_PIN_LENGTH); - mIndicatorType = typedArray.getInt(R.styleable.PinLockView_indicatorType, - IndicatorType.FIXED); - } finally { - typedArray.recycle(); - } - - initView(context); - } - - private void initView(Context context) { - ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR); - if (mIndicatorType == 0) { - for (int i = 0; i < mPinLength; i++) { - View dot = new View(context); - emptyDot(dot); - - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mDotDiameter, - mDotDiameter); - params.setMargins(mDotSpacing, 0, mDotSpacing, 0); - dot.setLayoutParams(params); - - addView(dot); - } - } else if (mIndicatorType == 2) { - setLayoutTransition(new LayoutTransition()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - // If the indicator type is not fixed - if (mIndicatorType != 0) { - ViewGroup.LayoutParams params = this.getLayoutParams(); - params.height = mDotDiameter; - requestLayout(); - } - } - - void updateDot(int length) { - if (mIndicatorType == 0) { - if (length > 0) { - if (length > mPreviousLength) { - fillDot(getChildAt(length - 1)); - } else { - emptyDot(getChildAt(length)); - } - mPreviousLength = length; - } else { - // When {@code mPinLength} is 0, we need to reset all the views back to empty - for (int i = 0; i < getChildCount(); i++) { - View v = getChildAt(i); - emptyDot(v); - } - mPreviousLength = 0; - } - } else { - if (length > 0) { - if (length > mPreviousLength) { - View dot = new View(getContext()); - fillDot(dot); - - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mDotDiameter, - mDotDiameter); - params.setMargins(mDotSpacing, 0, mDotSpacing, 0); - dot.setLayoutParams(params); - - addView(dot, length - 1); - } else { - removeViewAt(length); - } - mPreviousLength = length; - } else { - removeAllViews(); - mPreviousLength = 0; - } - } - } - - public void setErrorDots() { - for (int i = 0; i < getChildCount(); i++) { - View v = getChildAt(i); - errorDot(v); - } - } - - public void setSuccessDots() { - for (int i = 0; i < getChildCount(); i++) { - View v = getChildAt(i); - successDot(v); - } - } - - public void setDefaultDots() { -// for (int i = 0; i < getChildCount(); i++) { -// View v = getChildAt(i); -// emptyDot(v); -// } - removeAllViews(); - initView(getContext()); - mPreviousLength = 0; - } - - private void emptyDot(View dot) { - dot.setBackgroundResource(mEmptyDrawable); - } - - private void fillDot(View dot) { - dot.setBackgroundResource(mFillDrawable); - } - - private void errorDot(View dot) { - dot.setBackgroundResource(mErrorDrawable); - } - - private void successDot(View dot) { - dot.setBackgroundResource(mSuccessDrawable); - } - - public int getPinLength() { - return mPinLength; - } - - public void setPinLength(int pinLength) { - this.mPinLength = pinLength; - removeAllViews(); - initView(getContext()); - } - - public - @IndicatorType - int getIndicatorType() { - return mIndicatorType; - } - - public void setIndicatorType(@IndicatorType int type) { - this.mIndicatorType = type; - removeAllViews(); - initView(getContext()); - } - - @IntDef({IndicatorType.FIXED, IndicatorType.FILL, IndicatorType.FILL_WITH_ANIMATION}) - @Retention(RetentionPolicy.SOURCE) - public @interface IndicatorType { - int FIXED = 0; - int FILL = 1; - int FILL_WITH_ANIMATION = 2; - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.kt new file mode 100644 index 00000000..0c5dfd93 --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.kt @@ -0,0 +1,195 @@ +package com.andrognito.pinlockview + +import android.animation.LayoutTransition +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.LinearLayout +import androidx.annotation.IntDef +import androidx.core.view.ViewCompat + +/** + * It represents a set of indicator dots which when attached with [PinLockView] + * can be used to indicate the current length of the input + * + * + * Created by aritraroy on 01/06/16. + */ +class IndicatorDots @JvmOverloads constructor(context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) { + private var mDotDiameter: Int = 0 + private var mDotSpacing: Int = 0 + private var mFillDrawable: Int = 0 + private var mEmptyDrawable: Int = 0 + private var mErrorDrawable: Int = 0 + private var mSuccessDrawable: Int = 0 + private var mPinLength: Int = 0 + private var mIndicatorType: Int = 0 + private var mPreviousLength: Int = 0 + + var pinLength: Int + get() = mPinLength + set(pinLength) { + this.mPinLength = pinLength + removeAllViews() + initView(context) + } + + var indicatorType: Int + @IndicatorType + get() = mIndicatorType + set(@IndicatorType type) { + this.mIndicatorType = type + removeAllViews() + initView(context) + } + + init { + + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.PinLockView) + + try { + mDotDiameter = typedArray.getDimension(R.styleable.PinLockView_dotDiameter, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_dot_diameter)).toInt() + mDotSpacing = typedArray.getDimension(R.styleable.PinLockView_dotSpacing, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_dot_spacing)).toInt() + mFillDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, + R.drawable.dot_filled) + mErrorDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, + R.drawable.dot_error) + mSuccessDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotFilledBackground, + R.drawable.dot_success) + mEmptyDrawable = typedArray.getResourceId(R.styleable.PinLockView_dotEmptyBackground, + R.drawable.dot_empty) + mPinLength = typedArray.getInt(R.styleable.PinLockView_pinLength, DEFAULT_PIN_LENGTH) + mIndicatorType = typedArray.getInt(R.styleable.PinLockView_indicatorType, + IndicatorType.FIXED) + } finally { + typedArray.recycle() + } + + initView(context) + } + + private fun initView(context: Context) { + ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR) + if (mIndicatorType == 0) { + for (i in 0 until mPinLength) { + val dot = View(context) + emptyDot(dot) + + val params = LayoutParams(mDotDiameter, + mDotDiameter) + params.setMargins(mDotSpacing, 0, mDotSpacing, 0) + dot.layoutParams = params + + addView(dot) + } + } else if (mIndicatorType == 2) { + layoutTransition = LayoutTransition() + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + // If the indicator type is not fixed + if (mIndicatorType != 0) { + val params = this.layoutParams + params.height = mDotDiameter + requestLayout() + } + } + + internal fun updateDot(length: Int) { + if (mIndicatorType == 0) { + if (length > 0) { + if (length > mPreviousLength) { + fillDot(getChildAt(length - 1)) + } else { + emptyDot(getChildAt(length)) + } + mPreviousLength = length + } else { + // When {@code mPinLength} is 0, we need to reset all the views back to empty + for (i in 0 until childCount) { + val v = getChildAt(i) + emptyDot(v) + } + mPreviousLength = 0 + } + } else { + if (length > 0) { + if (length > mPreviousLength) { + val dot = View(context) + fillDot(dot) + + val params = LayoutParams(mDotDiameter, + mDotDiameter) + params.setMargins(mDotSpacing, 0, mDotSpacing, 0) + dot.layoutParams = params + + addView(dot, length - 1) + } else { + removeViewAt(length) + } + mPreviousLength = length + } else { + removeAllViews() + mPreviousLength = 0 + } + } + } + + fun setErrorDots() { + for (i in 0 until childCount) { + val v = getChildAt(i) + errorDot(v) + } + } + + fun setSuccessDots() { + for (i in 0 until childCount) { + val v = getChildAt(i) + successDot(v) + } + } + + fun setDefaultDots() { + // for (int i = 0; i < getChildCount(); i++) { + // View v = getChildAt(i); + // emptyDot(v); + // } + removeAllViews() + initView(context) + mPreviousLength = 0 + } + + private fun emptyDot(dot: View) { + dot.setBackgroundResource(mEmptyDrawable) + } + + private fun fillDot(dot: View) { + dot.setBackgroundResource(mFillDrawable) + } + + private fun errorDot(dot: View) { + dot.setBackgroundResource(mErrorDrawable) + } + + private fun successDot(dot: View) { + dot.setBackgroundResource(mSuccessDrawable) + } + + @IntDef(IndicatorType.FIXED, IndicatorType.FILL, IndicatorType.FILL_WITH_ANIMATION) + @Retention(AnnotationRetention.SOURCE) + annotation class IndicatorType { + companion object { + const val FIXED = 0 + const val FILL = 1 + const val FILL_WITH_ANIMATION = 2 + } + } + + companion object { + private const val DEFAULT_PIN_LENGTH = 4 + } +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.java b/pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.java deleted file mode 100644 index 490aa55a..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.andrognito.pinlockview; - -import android.graphics.Rect; -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; - -/** - * Created by aritraroy on 31/05/16. - */ -public class ItemSpaceDecoration extends RecyclerView.ItemDecoration { - - private final int mHorizontalSpaceWidth; - private final int mVerticalSpaceHeight; - private final int mSpanCount; - private final boolean mIncludeEdge; - - public ItemSpaceDecoration(int horizontalSpaceWidth, int verticalSpaceHeight, int spanCount, boolean includeEdge) { - this.mHorizontalSpaceWidth = horizontalSpaceWidth; - this.mVerticalSpaceHeight = verticalSpaceHeight; - this.mSpanCount = spanCount; - this.mIncludeEdge = includeEdge; - } - - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { - - int position = parent.getChildAdapterPosition(view); - int column = position % mSpanCount; - - if (mIncludeEdge) { - outRect.left = mHorizontalSpaceWidth - column * mHorizontalSpaceWidth / mSpanCount; - outRect.right = (column + 1) * mHorizontalSpaceWidth / mSpanCount; - - if (position < mSpanCount) { - outRect.top = mVerticalSpaceHeight; - } - outRect.bottom = mVerticalSpaceHeight; - } else { - outRect.left = column * mHorizontalSpaceWidth / mSpanCount; - outRect.right = mHorizontalSpaceWidth - (column + 1) * mHorizontalSpaceWidth / mSpanCount; - if (position >= mSpanCount) { - outRect.top = mVerticalSpaceHeight; - } - } - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.kt new file mode 100644 index 00000000..e7060049 --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/ItemSpaceDecoration.kt @@ -0,0 +1,37 @@ +package com.andrognito.pinlockview + +import android.graphics.Rect +import android.view.View + +import androidx.recyclerview.widget.RecyclerView + +/** + * Created by aritraroy on 31/05/16. + */ +class ItemSpaceDecoration(private val mHorizontalSpaceWidth: Int, + private val mVerticalSpaceHeight: Int, + private val mSpanCount: Int, + private val mIncludeEdge: Boolean) : RecyclerView.ItemDecoration() { + + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + + val position = parent.getChildAdapterPosition(view) + val column = position % mSpanCount + + if (mIncludeEdge) { + outRect.left = mHorizontalSpaceWidth - column * mHorizontalSpaceWidth / mSpanCount + outRect.right = (column + 1) * mHorizontalSpaceWidth / mSpanCount + + if (position < mSpanCount) { + outRect.top = mVerticalSpaceHeight + } + outRect.bottom = mVerticalSpaceHeight + } else { + outRect.left = column * mHorizontalSpaceWidth / mSpanCount + outRect.right = mHorizontalSpaceWidth - (column + 1) * mHorizontalSpaceWidth / mSpanCount + if (position >= mSpanCount) { + outRect.top = mVerticalSpaceHeight + } + } + } +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java b/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java deleted file mode 100644 index 60bf2625..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.andrognito.pinlockview; - -import android.content.Context; -import android.util.AttributeSet; - -import androidx.recyclerview.widget.GridLayoutManager; - -/** - * Used to always maintain an LTR layout no matter what is the real device's layout direction - * to avoid an unwanted reversed direction in RTL devices - * Created by Idan on 7/6/2017. - */ - -public class LTRGridLayoutManager extends GridLayoutManager { - - public LTRGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - public LTRGridLayoutManager(Context context, int spanCount) { - super(context, spanCount); - } - - public LTRGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { - super(context, spanCount, orientation, reverseLayout); - } - - @Override - protected boolean isLayoutRTL() { - return false; - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.kt new file mode 100644 index 00000000..45e3333c --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.kt @@ -0,0 +1,26 @@ +package com.andrognito.pinlockview + +import android.content.Context +import android.util.AttributeSet + +import androidx.recyclerview.widget.GridLayoutManager + +/** + * Used to always maintain an LTR layout no matter what is the real device's layout direction + * to avoid an unwanted reversed direction in RTL devices + * Created by Idan on 7/6/2017. + */ +class LTRGridLayoutManager : GridLayoutManager { + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) + : super(context, attrs, defStyleAttr, defStyleRes) + + constructor(context: Context, spanCount: Int) : super(context, spanCount) + + constructor(context: Context, spanCount: Int, orientation: Int, reverseLayout: Boolean) + : super(context, spanCount, orientation, reverseLayout) + + override fun isLayoutRTL(): Boolean { + return false + } +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java deleted file mode 100644 index 2b7d3a00..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java +++ /dev/null @@ -1,257 +0,0 @@ -package com.andrognito.pinlockview; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import androidx.recyclerview.widget.RecyclerView; - -/** - * Created by aritraroy on 31/05/16. - */ -public class PinLockAdapter extends RecyclerView.Adapter { - - private static final int VIEW_TYPE_NUMBER = 0; - private static final int VIEW_TYPE_DELETE = 1; - - private Context mContext; - private CustomizationOptionsBundle mCustomizationOptionsBundle; - private OnNumberClickListener mOnNumberClickListener; - private OnDeleteClickListener mOnDeleteClickListener; - private int mPinLength; - - private int[] mKeyValues; - - public PinLockAdapter(Context context) { - this.mContext = context; - this.mKeyValues = getAdjustKeyValues(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}); - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - RecyclerView.ViewHolder viewHolder; - LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - - if (viewType == VIEW_TYPE_NUMBER) { - View view = inflater.inflate(R.layout.layout_number_item, parent, false); - viewHolder = new NumberViewHolder(view); - } else { - View view = inflater.inflate(R.layout.layout_delete_item, parent, false); - viewHolder = new DeleteViewHolder(view); - } - return viewHolder; - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == VIEW_TYPE_NUMBER) { - NumberViewHolder vh1 = (NumberViewHolder) holder; - configureNumberButtonHolder(vh1, position); - } else if (holder.getItemViewType() == VIEW_TYPE_DELETE) { - DeleteViewHolder vh2 = (DeleteViewHolder) holder; - configureDeleteButtonHolder(vh2); - } - } - - private void configureNumberButtonHolder(NumberViewHolder holder, int position) { - if (holder != null) { - if (position == 9) { - holder.mNumberButton.setVisibility(View.GONE); - } else { - holder.mNumberButton.setText(String.valueOf(mKeyValues[position])); - holder.mNumberButton.setVisibility(View.VISIBLE); - holder.mNumberButton.setTag(mKeyValues[position]); - } - - if (mCustomizationOptionsBundle != null) { - holder.mNumberButton.setTextColor(mCustomizationOptionsBundle.getTextColor()); - if (mCustomizationOptionsBundle.getButtonBackgroundDrawable() != null) { - holder.mNumberButton.setBackground( - mCustomizationOptionsBundle.getButtonBackgroundDrawable()); - } - holder.mNumberButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, - mCustomizationOptionsBundle.getTextSize()); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - mCustomizationOptionsBundle.getButtonSize(), - mCustomizationOptionsBundle.getButtonSize()); - holder.mNumberButton.setLayoutParams(params); - } - } - } - - private void configureDeleteButtonHolder(DeleteViewHolder holder) { - if (holder != null) { - if (mCustomizationOptionsBundle.isShowDeleteButton() && mPinLength > 0) { - holder.mButtonImage.setVisibility(View.VISIBLE); - if (mCustomizationOptionsBundle.getDeleteButtonDrawable() != null) { - holder.mButtonImage.setImageDrawable(mCustomizationOptionsBundle.getDeleteButtonDrawable()); - } - holder.mButtonImage.setColorFilter(mCustomizationOptionsBundle.getTextColor(), - PorterDuff.Mode.SRC_ATOP); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - mCustomizationOptionsBundle.getDeleteButtonSize(), - mCustomizationOptionsBundle.getDeleteButtonSize()); - holder.mButtonImage.setLayoutParams(params); - } else { - holder.mButtonImage.setVisibility(View.GONE); - } - } - } - - @Override - public int getItemCount() { - return 12; - } - - @Override - public int getItemViewType(int position) { - if (position == getItemCount() - 1) { - return VIEW_TYPE_DELETE; - } - return VIEW_TYPE_NUMBER; - } - - public int getPinLength() { - return mPinLength; - } - - public void setPinLength(int pinLength) { - this.mPinLength = pinLength; - } - - public int[] getKeyValues() { - return mKeyValues; - } - - public void setKeyValues(int[] keyValues) { - this.mKeyValues = getAdjustKeyValues(keyValues); - notifyDataSetChanged(); - } - - private int[] getAdjustKeyValues(int[] keyValues) { - int[] adjustedKeyValues = new int[keyValues.length + 1]; - for (int i = 0; i < keyValues.length; i++) { - if (i < 9) { - adjustedKeyValues[i] = keyValues[i]; - } else { - adjustedKeyValues[i] = -1; - adjustedKeyValues[i + 1] = keyValues[i]; - } - } - return adjustedKeyValues; - } - - public OnNumberClickListener getOnItemClickListener() { - return mOnNumberClickListener; - } - - public void setOnItemClickListener(OnNumberClickListener onNumberClickListener) { - this.mOnNumberClickListener = onNumberClickListener; - } - - public OnDeleteClickListener getOnDeleteClickListener() { - return mOnDeleteClickListener; - } - - public void setOnDeleteClickListener(OnDeleteClickListener onDeleteClickListener) { - this.mOnDeleteClickListener = onDeleteClickListener; - } - - public CustomizationOptionsBundle getCustomizationOptions() { - return mCustomizationOptionsBundle; - } - - public void setCustomizationOptions(CustomizationOptionsBundle customizationOptionsBundle) { - this.mCustomizationOptionsBundle = customizationOptionsBundle; - } - - public interface OnNumberClickListener { - void onNumberClicked(int keyValue); - } - - public interface OnDeleteClickListener { - void onDeleteClicked(); - - void onDeleteLongClicked(); - } - - public class NumberViewHolder extends RecyclerView.ViewHolder { - Button mNumberButton; - - public NumberViewHolder(final View itemView) { - super(itemView); - mNumberButton = itemView.findViewById(R.id.button); - mNumberButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mOnNumberClickListener != null) { - mOnNumberClickListener.onNumberClicked((Integer) v.getTag()); - } - } - }); - } - } - - public class DeleteViewHolder extends RecyclerView.ViewHolder { - LinearLayout mDeleteButton; - ImageView mButtonImage; - - public DeleteViewHolder(final View itemView) { - super(itemView); - mDeleteButton = itemView.findViewById(R.id.button); - mButtonImage = itemView.findViewById(R.id.buttonImage); - - if (mCustomizationOptionsBundle.isShowDeleteButton() && mPinLength > 0) { - mDeleteButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mOnDeleteClickListener != null) { - mOnDeleteClickListener.onDeleteClicked(); - } - } - }); - - mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - if (mOnDeleteClickListener != null) { - mOnDeleteClickListener.onDeleteLongClicked(); - } - return true; - } - }); - - mDeleteButton.setOnTouchListener(new View.OnTouchListener() { - private Rect rect; - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - mButtonImage.setColorFilter(mCustomizationOptionsBundle - .getDeleteButtonPressesColor()); - rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); - } - if (event.getAction() == MotionEvent.ACTION_UP) { - mButtonImage.clearColorFilter(); - } - if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!rect.contains(v.getLeft() + (int) event.getX(), - v.getTop() + (int) event.getY())) { - mButtonImage.clearColorFilter(); - } - } - return false; - } - }); - } - } - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.kt new file mode 100644 index 00000000..9be92af9 --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.kt @@ -0,0 +1,205 @@ +package com.andrognito.pinlockview + +import android.content.Context +import android.graphics.PorterDuff +import android.graphics.Rect +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.LinearLayout + +import androidx.recyclerview.widget.RecyclerView + +/** + * Created by aritraroy on 31/05/16. + */ +class PinLockAdapter(private val mContext: Context) : RecyclerView.Adapter() { + var customizationOptions: CustomizationOptionsBundle? = null + var onItemClickListener: OnNumberClickListener? = null + var onDeleteClickListener: OnDeleteClickListener? = null + var pinLength: Int = 0 + + private var mKeyValues: IntArray? = null + + var keyValues: IntArray? + get() = mKeyValues + set(keyValues) { + this.mKeyValues = getAdjustKeyValues(keyValues!!) + notifyDataSetChanged() + } + + init { + this.mKeyValues = getAdjustKeyValues(intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val viewHolder: RecyclerView.ViewHolder + val inflater = LayoutInflater.from(parent.context) + + if (viewType == VIEW_TYPE_NUMBER) { + val view = inflater.inflate(R.layout.layout_number_item, parent, false) + viewHolder = NumberViewHolder(view) + } else { + val view = inflater.inflate(R.layout.layout_delete_item, parent, false) + viewHolder = DeleteViewHolder(view) + } + return viewHolder + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder.itemViewType == VIEW_TYPE_NUMBER) { + val vh1 = holder as NumberViewHolder + configureNumberButtonHolder(vh1, position) + } else if (holder.itemViewType == VIEW_TYPE_DELETE) { + val vh2 = holder as DeleteViewHolder + configureDeleteButtonHolder(vh2) + } + } + + private fun configureNumberButtonHolder(holder: NumberViewHolder?, position: Int) { + if (holder != null) { + if (position == 9) { + holder.mNumberButton.visibility = View.GONE + } else { + holder.mNumberButton.text = mKeyValues!![position].toString() + holder.mNumberButton.visibility = View.VISIBLE + holder.mNumberButton.tag = mKeyValues!![position] + } + + if (customizationOptions != null) { + holder.mNumberButton.setTextColor(customizationOptions!!.textColor) + if (customizationOptions!!.buttonBackgroundDrawable != null) { + holder.mNumberButton.background = customizationOptions!!.buttonBackgroundDrawable + } + holder.mNumberButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, + customizationOptions!!.textSize.toFloat()) + val params = LinearLayout.LayoutParams( + customizationOptions!!.buttonSize, + customizationOptions!!.buttonSize) + holder.mNumberButton.layoutParams = params + } + } + } + + private fun configureDeleteButtonHolder(holder: DeleteViewHolder?) { + if (holder != null) { + if (customizationOptions!!.isShowDeleteButton && pinLength > 0) { + holder.mButtonImage.visibility = View.VISIBLE + if (customizationOptions!!.deleteButtonDrawable != null) { + holder.mButtonImage.setImageDrawable(customizationOptions!!.deleteButtonDrawable) + } + holder.mButtonImage.setColorFilter(customizationOptions!!.textColor, + PorterDuff.Mode.SRC_ATOP) + val params = LinearLayout.LayoutParams( + customizationOptions!!.deleteButtonSize, + customizationOptions!!.deleteButtonSize) + holder.mButtonImage.layoutParams = params + } else { + holder.mButtonImage.visibility = View.GONE + } + } + } + + override fun getItemCount(): Int { + return 12 + } + + override fun getItemViewType(position: Int): Int { + return if (position == itemCount - 1) { + VIEW_TYPE_DELETE + } else VIEW_TYPE_NUMBER + } + + private fun getAdjustKeyValues(keyValues: IntArray): IntArray { + val adjustedKeyValues = IntArray(keyValues.size + 1) + for (i in keyValues.indices) { + if (i < 9) { + adjustedKeyValues[i] = keyValues[i] + } else { + adjustedKeyValues[i] = -1 + adjustedKeyValues[i + 1] = keyValues[i] + } + } + return adjustedKeyValues + } + + interface OnNumberClickListener { + fun onNumberClicked(keyValue: Int) + } + + interface OnDeleteClickListener { + fun onDeleteClicked() + + fun onDeleteLongClicked() + } + + inner class NumberViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + internal var mNumberButton: Button + + init { + mNumberButton = itemView.findViewById(R.id.button) + mNumberButton.setOnClickListener { v -> + if (onItemClickListener != null) { + onItemClickListener!!.onNumberClicked(v.tag as Int) + } + } + } + } + + inner class DeleteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + internal var mDeleteButton: LinearLayout + internal var mButtonImage: ImageView + + init { + mDeleteButton = itemView.findViewById(R.id.button) + mButtonImage = itemView.findViewById(R.id.buttonImage) + + if (customizationOptions!!.isShowDeleteButton && pinLength > 0) { + mDeleteButton.setOnClickListener { + if (onDeleteClickListener != null) { + onDeleteClickListener!!.onDeleteClicked() + } + } + + mDeleteButton.setOnLongClickListener { + if (onDeleteClickListener != null) { + onDeleteClickListener!!.onDeleteLongClicked() + } + true + } + + mDeleteButton.setOnTouchListener(object : View.OnTouchListener { + private var rect: Rect? = null + + override fun onTouch(v: View, event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_DOWN) { + mButtonImage.setColorFilter(customizationOptions!! + .deleteButtonPressesColor) + rect = Rect(v.left, v.top, v.right, v.bottom) + } + if (event.action == MotionEvent.ACTION_UP) { + mButtonImage.clearColorFilter() + } + if (event.action == MotionEvent.ACTION_MOVE) { + if (!rect!!.contains(v.left + event.x.toInt(), + v.top + event.y.toInt())) { + mButtonImage.clearColorFilter() + } + } + return false + } + }) + } + } + } + + companion object { + + private const val VIEW_TYPE_NUMBER = 0 + private const val VIEW_TYPE_DELETE = 1 + } +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockListener.java b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockListener.kt similarity index 63% rename from pinlockview/src/main/java/com/andrognito/pinlockview/PinLockListener.java rename to pinlockview/src/main/java/com/andrognito/pinlockview/PinLockListener.kt index fcb00f9f..7ad08c46 100644 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockListener.java +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockListener.kt @@ -1,12 +1,12 @@ -package com.andrognito.pinlockview; +package com.andrognito.pinlockview /** * The listener that triggers callbacks for various events - * in the {@link PinLockView} + * in the [PinLockView] * * Created by aritraroy on 31/05/16. */ -public interface PinLockListener { +interface PinLockListener { /** * Triggers when the complete pin is entered, @@ -14,19 +14,19 @@ public interface PinLockListener { * * @param pin the complete pin */ - void onComplete(String pin); + fun onComplete(pin: String) /** * Triggers when the pin is empty after manual deletion */ - void onEmpty(); + fun onEmpty() /** - * Triggers on a key press on the {@link PinLockView} + * Triggers on a key press on the [PinLockView] * * @param pinLength the current pin length * @param intermediatePin the intermediate pin */ - void onPinChange(int pinLength, String intermediatePin); + fun onPinChange(pinLength: Int, intermediatePin: String) } diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java deleted file mode 100644 index 28fbcdb3..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java +++ /dev/null @@ -1,433 +0,0 @@ -package com.andrognito.pinlockview; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; - -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; - -/** - * Represents a numeric lock view which can used to taken numbers as input. - * The length of the input can be customized using {@link PinLockView#setPinLength(int)}, the default value being 4 - *

- * It can also be used as dial pad for taking number inputs. - * Optionally, {@link IndicatorDots} can be attached to this view to indicate the length of the input taken - * Created by aritraroy on 31/05/16. - */ -public class PinLockView extends RecyclerView { - - private static final int DEFAULT_PIN_LENGTH = 4; - private static final int[] DEFAULT_KEY_SET = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; - - private String mPin = ""; - private int mPinLength; - private int mHorizontalSpacing, mVerticalSpacing; - private int mTextColor, mDeleteButtonPressedColor; - private int mTextSize, mButtonSize, mDeleteButtonSize; - private Drawable mButtonBackgroundDrawable; - private Drawable mDeleteButtonDrawable; - private boolean mShowDeleteButton; - - private IndicatorDots mIndicatorDots; - private PinLockAdapter mAdapter; - private PinLockListener mPinLockListener; - private CustomizationOptionsBundle mCustomizationOptionsBundle; - private int[] mCustomKeySet; - - private PinLockAdapter.OnNumberClickListener mOnNumberClickListener - = new PinLockAdapter.OnNumberClickListener() { - @Override - public void onNumberClicked(int keyValue) { - if (mPin.length() < getPinLength()) { - mPin = mPin.concat(String.valueOf(keyValue)); - - if (isIndicatorDotsAttached()) { - mIndicatorDots.updateDot(mPin.length()); - } - - if (mPin.length() == 1) { - mAdapter.setPinLength(mPin.length()); - mAdapter.notifyItemChanged(mAdapter.getItemCount() - 1); - } - - if (mPinLockListener != null) { - if (mPin.length() == mPinLength) { - mPinLockListener.onComplete(mPin); - } else { - mPinLockListener.onPinChange(mPin.length(), mPin); - } - } - } else { - if (!isShowDeleteButton()) { - resetPinLockView(); - mPin = mPin.concat(String.valueOf(keyValue)); - - if (isIndicatorDotsAttached()) { - mIndicatorDots.updateDot(mPin.length()); - } - - if (mPinLockListener != null) { - mPinLockListener.onPinChange(mPin.length(), mPin); - } - - } else { - if (mPinLockListener != null) { - mPinLockListener.onComplete(mPin); - } - } - } - } - }; - - private PinLockAdapter.OnDeleteClickListener mOnDeleteClickListener - = new PinLockAdapter.OnDeleteClickListener() { - @Override - public void onDeleteClicked() { - if (mPin.length() > 0) { - mPin = mPin.substring(0, mPin.length() - 1); - - if (isIndicatorDotsAttached()) { - mIndicatorDots.updateDot(mPin.length()); - } - - if (mPin.length() == 0) { - mAdapter.setPinLength(mPin.length()); - mAdapter.notifyItemChanged(mAdapter.getItemCount() - 1); - } - - if (mPinLockListener != null) { - if (mPin.length() == 0) { - mPinLockListener.onEmpty(); - clearInternalPin(); - } else { - mPinLockListener.onPinChange(mPin.length(), mPin); - } - } - } else { - if (mPinLockListener != null) { - mPinLockListener.onEmpty(); - } - } - } - - @Override - public void onDeleteLongClicked() { - resetPinLockView(); - if (mPinLockListener != null) { - mPinLockListener.onEmpty(); - } - } - }; - - public PinLockView(Context context) { - super(context); - init(null, 0); - } - - public PinLockView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(attrs, 0); - } - - public PinLockView(Context context, @Nullable AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(attrs, defStyle); - } - - private void init(AttributeSet attributeSet, int defStyle) { - - TypedArray typedArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.PinLockView); - - try { - mPinLength = typedArray.getInt(R.styleable.PinLockView_pinLength, DEFAULT_PIN_LENGTH); - mHorizontalSpacing = (int) typedArray.getDimension(R.styleable.PinLockView_keypadHorizontalSpacing, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_horizontal_spacing)); - mVerticalSpacing = (int) typedArray.getDimension(R.styleable.PinLockView_keypadVerticalSpacing, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_vertical_spacing)); - mTextColor = typedArray.getColor(R.styleable.PinLockView_keypadTextColor, ResourceUtils.getColor(getContext(), R.color.white)); - mTextSize = (int) typedArray.getDimension(R.styleable.PinLockView_keypadTextSize, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_text_size)); - mButtonSize = (int) typedArray.getDimension(R.styleable.PinLockView_keypadButtonSize, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_button_size)); - mDeleteButtonSize = (int) typedArray.getDimension(R.styleable.PinLockView_keypadDeleteButtonSize, ResourceUtils.getDimensionInPx(getContext(), R.dimen.default_delete_button_size)); - mButtonBackgroundDrawable = typedArray.getDrawable(R.styleable.PinLockView_keypadButtonBackgroundDrawable); - mDeleteButtonDrawable = typedArray.getDrawable(R.styleable.PinLockView_keypadDeleteButtonDrawable); - mShowDeleteButton = typedArray.getBoolean(R.styleable.PinLockView_keypadShowDeleteButton, true); - mDeleteButtonPressedColor = typedArray.getColor(R.styleable.PinLockView_keypadDeleteButtonPressedColor, ResourceUtils.getColor(getContext(), R.color.greyish)); - } finally { - typedArray.recycle(); - } - - mCustomizationOptionsBundle = new CustomizationOptionsBundle(); - mCustomizationOptionsBundle.setTextColor(mTextColor); - mCustomizationOptionsBundle.setTextSize(mTextSize); - mCustomizationOptionsBundle.setButtonSize(mButtonSize); - mCustomizationOptionsBundle.setButtonBackgroundDrawable(mButtonBackgroundDrawable); - mCustomizationOptionsBundle.setDeleteButtonDrawable(mDeleteButtonDrawable); - mCustomizationOptionsBundle.setDeleteButtonSize(mDeleteButtonSize); - mCustomizationOptionsBundle.setShowDeleteButton(mShowDeleteButton); - mCustomizationOptionsBundle.setDeleteButtonPressesColor(mDeleteButtonPressedColor); - - initView(); - } - - private void initView() { - setLayoutManager(new LTRGridLayoutManager(getContext(), 3)); - - mAdapter = new PinLockAdapter(getContext()); - mAdapter.setOnItemClickListener(mOnNumberClickListener); - mAdapter.setOnDeleteClickListener(mOnDeleteClickListener); - mAdapter.setCustomizationOptions(mCustomizationOptionsBundle); - setAdapter(mAdapter); - - addItemDecoration(new ItemSpaceDecoration(mHorizontalSpacing, mVerticalSpacing, 3, false)); - setOverScrollMode(OVER_SCROLL_NEVER); - } - - /** - * Sets a {@link PinLockListener} to the to listen to pin update events - * - * @param pinLockListener the listener - */ - public void setPinLockListener(PinLockListener pinLockListener) { - this.mPinLockListener = pinLockListener; - } - - /** - * Get the length of the current pin length - * - * @return the length of the pin - */ - public int getPinLength() { - return mPinLength; - } - - /** - * Sets the pin length dynamically - * - * @param pinLength the pin length - */ - public void setPinLength(int pinLength) { - this.mPinLength = pinLength; - - if (isIndicatorDotsAttached()) { - mIndicatorDots.setPinLength(pinLength); - } - } - - /** - * Get the text color in the buttons - * - * @return the text color - */ - public int getTextColor() { - return mTextColor; - } - - /** - * Set the text color of the buttons dynamically - * - * @param textColor the text color - */ - public void setTextColor(int textColor) { - this.mTextColor = textColor; - mCustomizationOptionsBundle.setTextColor(textColor); - mAdapter.notifyDataSetChanged(); - } - - /** - * Get the size of the text in the buttons - * - * @return the size of the text in pixels - */ - public int getTextSize() { - return mTextSize; - } - - /** - * Set the size of text in pixels - * - * @param textSize the text size in pixels - */ - public void setTextSize(int textSize) { - this.mTextSize = textSize; - mCustomizationOptionsBundle.setTextSize(textSize); - mAdapter.notifyDataSetChanged(); - } - - /** - * Get the size of the pin buttons - * - * @return the size of the button in pixels - */ - public int getButtonSize() { - return mButtonSize; - } - - /** - * Set the size of the pin buttons dynamically - * - * @param buttonSize the button size - */ - public void setButtonSize(int buttonSize) { - this.mButtonSize = buttonSize; - mCustomizationOptionsBundle.setButtonSize(buttonSize); - mAdapter.notifyDataSetChanged(); - } - - /** - * Get the current background drawable of the buttons, can be null - * - * @return the background drawable - */ - public Drawable getButtonBackgroundDrawable() { - return mButtonBackgroundDrawable; - } - - /** - * Set the background drawable of the buttons dynamically - * - * @param buttonBackgroundDrawable the background drawable - */ - public void setButtonBackgroundDrawable(Drawable buttonBackgroundDrawable) { - this.mButtonBackgroundDrawable = buttonBackgroundDrawable; - mCustomizationOptionsBundle.setButtonBackgroundDrawable(buttonBackgroundDrawable); - mAdapter.notifyDataSetChanged(); - } - - /** - * Get the drawable of the delete button - * - * @return the delete button drawable - */ - public Drawable getDeleteButtonDrawable() { - return mDeleteButtonDrawable; - } - - /** - * Set the drawable of the delete button dynamically - * - * @param deleteBackgroundDrawable the delete button drawable - */ - public void setDeleteButtonDrawable(Drawable deleteBackgroundDrawable) { - this.mDeleteButtonDrawable = deleteBackgroundDrawable; - mCustomizationOptionsBundle.setDeleteButtonDrawable(deleteBackgroundDrawable); - mAdapter.notifyDataSetChanged(); - } - - /** - * Get the delete button size in pixels - * - * @return size in pixels - */ - public int getDeleteButtonSize() { - return mDeleteButtonSize; - } - - /** - * Set the size of the delete button in pixels - * - * @param deleteButtonSize size in pixels - */ - public void setDeleteButtonSize(int deleteButtonSize) { - this.mDeleteButtonSize = deleteButtonSize; - mCustomizationOptionsBundle.setDeleteButtonSize(deleteButtonSize); - mAdapter.notifyDataSetChanged(); - } - - /** - * Is the delete button shown - * - * @return returns true if shown, false otherwise - */ - public boolean isShowDeleteButton() { - return mShowDeleteButton; - } - - /** - * Dynamically set if the delete button should be shown - * - * @param showDeleteButton true if the delete button should be shown, false otherwise - */ - public void setShowDeleteButton(boolean showDeleteButton) { - this.mShowDeleteButton = showDeleteButton; - mCustomizationOptionsBundle.setShowDeleteButton(showDeleteButton); - mAdapter.notifyDataSetChanged(); - } - - /** - * Get the delete button pressed/focused state color - * - * @return color of the button - */ - public int getDeleteButtonPressedColor() { - return mDeleteButtonPressedColor; - } - - /** - * Set the pressed/focused state color of the delete button - * - * @param deleteButtonPressedColor the color of the delete button - */ - public void setDeleteButtonPressedColor(int deleteButtonPressedColor) { - this.mDeleteButtonPressedColor = deleteButtonPressedColor; - mCustomizationOptionsBundle.setDeleteButtonPressesColor(deleteButtonPressedColor); - mAdapter.notifyDataSetChanged(); - } - - public int[] getCustomKeySet() { - return mCustomKeySet; - } - - public void setCustomKeySet(int[] customKeySet) { - this.mCustomKeySet = customKeySet; - - if (mAdapter != null) { - mAdapter.setKeyValues(customKeySet); - } - } - - public void enableLayoutShuffling() { - this.mCustomKeySet = ShuffleArrayUtils.shuffle(DEFAULT_KEY_SET); - - if (mAdapter != null) { - mAdapter.setKeyValues(mCustomKeySet); - } - } - - private void clearInternalPin() { - mPin = ""; - } - - /** - * Resets the {@link PinLockView}, clearing the entered pin - * and resetting the {@link IndicatorDots} if attached - */ - public void resetPinLockView() { - - clearInternalPin(); - - mAdapter.setPinLength(mPin.length()); - mAdapter.notifyItemChanged(mAdapter.getItemCount() - 1); - - if (mIndicatorDots != null) { - mIndicatorDots.updateDot(mPin.length()); - } - } - - /** - * Returns true if {@link IndicatorDots} are attached to {@link PinLockView} - * - * @return true if attached, false otherwise - */ - public boolean isIndicatorDotsAttached() { - return mIndicatorDots != null; - } - - /** - * Attaches {@link IndicatorDots} to {@link PinLockView} - * - * @param mIndicatorDots the view to attach - */ - public void attachIndicatorDots(IndicatorDots mIndicatorDots) { - this.mIndicatorDots = mIndicatorDots; - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.kt new file mode 100644 index 00000000..b25e01e9 --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.kt @@ -0,0 +1,411 @@ +package com.andrognito.pinlockview + +import android.content.Context +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +/** + * Represents a numeric lock view which can used to taken numbers as input. + * The length of the input can be customized using [PinLockView.setPinLength], the default value being 4 + * + * + * It can also be used as dial pad for taking number inputs. + * Optionally, [IndicatorDots] can be attached to this view to indicate the length of the input taken + * Created by aritraroy on 31/05/16. + */ +class PinLockView : RecyclerView { + + private var mPin = "" + private var mPinLength: Int = 0 + private var mHorizontalSpacing: Int = 0 + private var mVerticalSpacing: Int = 0 + private var mTextColor: Int = 0 + private var mDeleteButtonPressedColor: Int = 0 + private var mTextSize: Int = 0 + private var mButtonSize: Int = 0 + private var mDeleteButtonSize: Int = 0 + private var mButtonBackgroundDrawable: Drawable? = null + private var mDeleteButtonDrawable: Drawable? = null + private var mShowDeleteButton: Boolean = false + + private var mIndicatorDots: IndicatorDots? = null + private var mAdapter: PinLockAdapter? = null + private var mPinLockListener: PinLockListener? = null + private var mCustomizationOptionsBundle: CustomizationOptionsBundle? = null + private var mCustomKeySet: IntArray? = null + + private val mOnNumberClickListener = object : PinLockAdapter.OnNumberClickListener { + override fun onNumberClicked(keyValue: Int) { + + if (mPin.length < pinLength) { + mPin += keyValue.toString() + + if (isIndicatorDotsAttached) { + mIndicatorDots!!.updateDot(mPin.length) + } + + if (mPin.length == 1) { + mAdapter!!.pinLength = mPin.length + mAdapter!!.notifyItemChanged(mAdapter!!.itemCount - 1) + } + + if (mPinLockListener != null) { + if (mPin.length == mPinLength) { + mPinLockListener!!.onComplete(mPin) + } else { + mPinLockListener!!.onPinChange(mPin.length, mPin) + } + } + } else { + if (!isShowDeleteButton) { + resetPinLockView() + mPin += keyValue.toString() + + if (isIndicatorDotsAttached) { + mIndicatorDots!!.updateDot(mPin.length) + } + + if (mPinLockListener != null) { + mPinLockListener!!.onPinChange(mPin.length, mPin) + } + + } else { + if (mPinLockListener != null) { + mPinLockListener!!.onComplete(mPin) + } + } + } + } + } + + private val mOnDeleteClickListener = object : PinLockAdapter.OnDeleteClickListener { + override fun onDeleteClicked() { + if (mPin.isNotEmpty()) { + mPin = mPin.substring(0, mPin.length - 1) + + if (isIndicatorDotsAttached) { + mIndicatorDots!!.updateDot(mPin.length) + } + + if (mPin.isEmpty()) { + mAdapter!!.pinLength = mPin.length + mAdapter!!.notifyItemChanged(mAdapter!!.itemCount - 1) + } + + if (mPinLockListener != null) { + if (mPin.isEmpty()) { + mPinLockListener!!.onEmpty() + clearInternalPin() + } else { + mPinLockListener!!.onPinChange(mPin.length, mPin) + } + } + } else { + if (mPinLockListener != null) { + mPinLockListener!!.onEmpty() + } + } + } + + override fun onDeleteLongClicked() { + resetPinLockView() + if (mPinLockListener != null) { + mPinLockListener!!.onEmpty() + } + } + } + + /** + * Get the length of the current pin length + * + * @return the length of the pin + */ + /** + * Sets the pin length dynamically + * + * @param pinLength the pin length + */ + var pinLength: Int + get() = mPinLength + set(pinLength) { + this.mPinLength = pinLength + + if (isIndicatorDotsAttached) { + mIndicatorDots!!.pinLength = pinLength + } + } + + /** + * Get the text color in the buttons + * + * @return the text color + */ + /** + * Set the text color of the buttons dynamically + * + * @param textColor the text color + */ + var textColor: Int + get() = mTextColor + set(textColor) { + this.mTextColor = textColor + mCustomizationOptionsBundle!!.textColor = textColor + mAdapter!!.notifyDataSetChanged() + } + + /** + * Get the size of the text in the buttons + * + * @return the size of the text in pixels + */ + /** + * Set the size of text in pixels + * + * @param textSize the text size in pixels + */ + var textSize: Int + get() = mTextSize + set(textSize) { + this.mTextSize = textSize + mCustomizationOptionsBundle!!.textSize = textSize + mAdapter!!.notifyDataSetChanged() + } + + /** + * Get the size of the pin buttons + * + * @return the size of the button in pixels + */ + /** + * Set the size of the pin buttons dynamically + * + * @param buttonSize the button size + */ + var buttonSize: Int + get() = mButtonSize + set(buttonSize) { + this.mButtonSize = buttonSize + mCustomizationOptionsBundle!!.buttonSize = buttonSize + mAdapter!!.notifyDataSetChanged() + } + + /** + * Get the current background drawable of the buttons, can be null + * + * @return the background drawable + */ + /** + * Set the background drawable of the buttons dynamically + * + * @param buttonBackgroundDrawable the background drawable + */ + var buttonBackgroundDrawable: Drawable? + get() = mButtonBackgroundDrawable + set(buttonBackgroundDrawable) { + this.mButtonBackgroundDrawable = buttonBackgroundDrawable + mCustomizationOptionsBundle!!.buttonBackgroundDrawable = buttonBackgroundDrawable + mAdapter!!.notifyDataSetChanged() + } + + /** + * Get the drawable of the delete button + * + * @return the delete button drawable + */ + /** + * Set the drawable of the delete button dynamically + * + * @param deleteBackgroundDrawable the delete button drawable + */ + var deleteButtonDrawable: Drawable? + get() = mDeleteButtonDrawable + set(deleteBackgroundDrawable) { + this.mDeleteButtonDrawable = deleteBackgroundDrawable + mCustomizationOptionsBundle!!.deleteButtonDrawable = deleteBackgroundDrawable + mAdapter!!.notifyDataSetChanged() + } + + /** + * Get the delete button size in pixels + * + * @return size in pixels + */ + /** + * Set the size of the delete button in pixels + * + * @param deleteButtonSize size in pixels + */ + var deleteButtonSize: Int + get() = mDeleteButtonSize + set(deleteButtonSize) { + this.mDeleteButtonSize = deleteButtonSize + mCustomizationOptionsBundle!!.deleteButtonSize = deleteButtonSize + mAdapter!!.notifyDataSetChanged() + } + + /** + * Is the delete button shown + * + * @return returns true if shown, false otherwise + */ + /** + * Dynamically set if the delete button should be shown + * + * @param showDeleteButton true if the delete button should be shown, false otherwise + */ + var isShowDeleteButton: Boolean + get() = mShowDeleteButton + set(showDeleteButton) { + this.mShowDeleteButton = showDeleteButton + mCustomizationOptionsBundle!!.isShowDeleteButton = showDeleteButton + mAdapter!!.notifyDataSetChanged() + } + + /** + * Get the delete button pressed/focused state color + * + * @return color of the button + */ + /** + * Set the pressed/focused state color of the delete button + * + * @param deleteButtonPressedColor the color of the delete button + */ + var deleteButtonPressedColor: Int + get() = mDeleteButtonPressedColor + set(deleteButtonPressedColor) { + this.mDeleteButtonPressedColor = deleteButtonPressedColor + mCustomizationOptionsBundle!!.deleteButtonPressesColor = deleteButtonPressedColor + mAdapter!!.notifyDataSetChanged() + } + + var customKeySet: IntArray? + get() = mCustomKeySet + set(customKeySet) { + this.mCustomKeySet = customKeySet + + if (mAdapter != null) { + mAdapter!!.keyValues = customKeySet + } + } + + /** + * Returns true if [IndicatorDots] are attached to [PinLockView] + * + * @return true if attached, false otherwise + */ + val isIndicatorDotsAttached: Boolean + get() = mIndicatorDots != null + + constructor(context: Context) : super(context) { + init(null, 0) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init(attrs, 0) + } + + constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) { + init(attrs, defStyle) + } + + private fun init(attributeSet: AttributeSet?, defStyle: Int) { + + val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.PinLockView) + + try { + mPinLength = typedArray.getInt(R.styleable.PinLockView_pinLength, DEFAULT_PIN_LENGTH) + mHorizontalSpacing = typedArray.getDimension(R.styleable.PinLockView_keypadHorizontalSpacing, ResourceUtils.getDimensionInPx(context, R.dimen.default_horizontal_spacing)).toInt() + mVerticalSpacing = typedArray.getDimension(R.styleable.PinLockView_keypadVerticalSpacing, ResourceUtils.getDimensionInPx(context, R.dimen.default_vertical_spacing)).toInt() + mTextColor = typedArray.getColor(R.styleable.PinLockView_keypadTextColor, ResourceUtils.getColor(context, R.color.white)) + mTextSize = typedArray.getDimension(R.styleable.PinLockView_keypadTextSize, ResourceUtils.getDimensionInPx(context, R.dimen.default_text_size)).toInt() + mButtonSize = typedArray.getDimension(R.styleable.PinLockView_keypadButtonSize, ResourceUtils.getDimensionInPx(context, R.dimen.default_button_size)).toInt() + mDeleteButtonSize = typedArray.getDimension(R.styleable.PinLockView_keypadDeleteButtonSize, ResourceUtils.getDimensionInPx(context, R.dimen.default_delete_button_size)).toInt() + mButtonBackgroundDrawable = typedArray.getDrawable(R.styleable.PinLockView_keypadButtonBackgroundDrawable) + mDeleteButtonDrawable = typedArray.getDrawable(R.styleable.PinLockView_keypadDeleteButtonDrawable) + mShowDeleteButton = typedArray.getBoolean(R.styleable.PinLockView_keypadShowDeleteButton, true) + mDeleteButtonPressedColor = typedArray.getColor(R.styleable.PinLockView_keypadDeleteButtonPressedColor, ResourceUtils.getColor(context, R.color.greyish)) + } finally { + typedArray.recycle() + } + + mCustomizationOptionsBundle = CustomizationOptionsBundle() + mCustomizationOptionsBundle!!.textColor = mTextColor + mCustomizationOptionsBundle!!.textSize = mTextSize + mCustomizationOptionsBundle!!.buttonSize = mButtonSize + mCustomizationOptionsBundle!!.buttonBackgroundDrawable = mButtonBackgroundDrawable + mCustomizationOptionsBundle!!.deleteButtonDrawable = mDeleteButtonDrawable + mCustomizationOptionsBundle!!.deleteButtonSize = mDeleteButtonSize + mCustomizationOptionsBundle!!.isShowDeleteButton = mShowDeleteButton + mCustomizationOptionsBundle!!.deleteButtonPressesColor = mDeleteButtonPressedColor + + initView() + } + + private fun initView() { + layoutManager = LTRGridLayoutManager(context, 3) + + mAdapter = PinLockAdapter(context) + mAdapter!!.onItemClickListener = mOnNumberClickListener + mAdapter!!.onDeleteClickListener = mOnDeleteClickListener + mAdapter!!.customizationOptions = mCustomizationOptionsBundle + adapter = mAdapter + + addItemDecoration(ItemSpaceDecoration(mHorizontalSpacing, mVerticalSpacing, 3, false)) + overScrollMode = View.OVER_SCROLL_NEVER + } + + /** + * Sets a [PinLockListener] to the to listen to pin update events + * + * @param pinLockListener the listener + */ + fun setPinLockListener(pinLockListener: PinLockListener) { + this.mPinLockListener = pinLockListener + } + + fun enableLayoutShuffling() { + this.mCustomKeySet = ShuffleArrayUtils.shuffle(DEFAULT_KEY_SET) + + if (mAdapter != null) { + mAdapter!!.keyValues = mCustomKeySet + } + } + + private fun clearInternalPin() { + mPin = "" + } + + /** + * Resets the [PinLockView], clearing the entered pin + * and resetting the [IndicatorDots] if attached + */ + fun resetPinLockView() { + + clearInternalPin() + + mAdapter!!.pinLength = mPin.length + mAdapter!!.notifyItemChanged(mAdapter!!.itemCount - 1) + + if (mIndicatorDots != null) { + mIndicatorDots!!.updateDot(mPin.length) + } + } + + /** + * Attaches [IndicatorDots] to [PinLockView] + * + * @param mIndicatorDots the view to attach + */ + fun attachIndicatorDots(mIndicatorDots: IndicatorDots) { + this.mIndicatorDots = mIndicatorDots + } + + companion object { + + private const val DEFAULT_PIN_LENGTH = 4 + private val DEFAULT_KEY_SET = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) + } +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java b/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java deleted file mode 100644 index f75f301c..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.andrognito.pinlockview; - -import android.content.Context; -import android.graphics.drawable.Drawable; - -import androidx.annotation.ColorRes; -import androidx.annotation.DimenRes; -import androidx.annotation.DrawableRes; -import androidx.core.content.ContextCompat; - -/** - * Created by aritraroy on 10/06/16. - */ -public class ResourceUtils { - - private ResourceUtils() { - throw new AssertionError(); - } - - public static int getColor(Context context, @ColorRes int id) { - return ContextCompat.getColor(context, id); - } - - public static float getDimensionInPx(Context context, @DimenRes int id) { - return context.getResources().getDimension(id); - } - - public static Drawable getDrawable(Context context, @DrawableRes int id) { - return ContextCompat.getDrawable(context, id); - } -} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.kt new file mode 100644 index 00000000..b1b46d0b --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/ResourceUtils.kt @@ -0,0 +1,34 @@ +package com.andrognito.pinlockview + +import android.content.Context +import android.graphics.drawable.Drawable + +import androidx.annotation.ColorRes +import androidx.annotation.DimenRes +import androidx.annotation.DrawableRes +import androidx.core.content.ContextCompat + +/** + * Created by aritraroy on 10/06/16. + */ +class ResourceUtils private constructor() { + + init { + throw AssertionError() + } + + companion object { + + fun getColor(context: Context, @ColorRes id: Int): Int { + return ContextCompat.getColor(context, id) + } + + fun getDimensionInPx(context: Context, @DimenRes id: Int): Float { + return context.resources.getDimension(id) + } + + fun getDrawable(context: Context, @DrawableRes id: Int): Drawable? { + return ContextCompat.getDrawable(context, id) + } + } +} diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.java b/pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.java deleted file mode 100644 index 9475a946..00000000 --- a/pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.andrognito.pinlockview; - -import java.util.Random; - -/** - * Created by aritraroy on 10/03/17. - */ - -public class ShuffleArrayUtils { - - /** - * Shuffle an array - * - * @param array - */ - static int[] shuffle(int[] array) { - int length = array.length; - Random random = new Random(); - random.nextInt(); - - for (int i = 0; i < length; i++) { - int change = i + random.nextInt(length - i); - swap(array, i, change); - } - return array; - } - - private static void swap(int[] array, int index, int change) { - int temp = array[index]; - array[index] = array[change]; - array[change] = temp; - } -} \ No newline at end of file diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.kt b/pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.kt new file mode 100644 index 00000000..8bd96b7c --- /dev/null +++ b/pinlockview/src/main/java/com/andrognito/pinlockview/ShuffleArrayUtils.kt @@ -0,0 +1,33 @@ +package com.andrognito.pinlockview + +import java.util.* + +/** + * Created by aritraroy on 10/03/17. + */ + +object ShuffleArrayUtils { + + /** + * Shuffle an array + * + * @param array + */ + internal fun shuffle(array: IntArray): IntArray { + val length = array.size + val random = Random() + random.nextInt() + + for (i in 0 until length) { + val change = i + random.nextInt(length - i) + swap(array, i, change) + } + return array + } + + private fun swap(array: IntArray, index: Int, change: Int) { + val temp = array[index] + array[index] = array[change] + array[change] = temp + } +} \ No newline at end of file From e6e98673a18a2f5c5ea054264226b3f74e80d20f Mon Sep 17 00:00:00 2001 From: dmitriy Date: Wed, 24 Apr 2019 21:36:01 +0300 Subject: [PATCH 5/5] in progress --- .../andrognito/pinlockviewapp/SampleActivity.kt | 15 +++++++++++---- pinlockview/src/main/res/values/colors.xml | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt index a51f043c..3de7ce69 100644 --- a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt +++ b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.kt @@ -22,9 +22,12 @@ class SampleActivity : AppCompatActivity() { override fun onComplete(pin: String) { Log.d(TAG, "Pin complete: $pin") val shake = AnimationUtils.loadAnimation(this@SampleActivity, R.anim.shake_wrong) - mIndicatorDotsFirst!!.startAnimation(shake) - // mIndicatorDotsFirst.setErrorDots(); - mIndicatorDotsFirst!!.setSuccessDots() + if (pin == "1111") { + mIndicatorDotsFirst!!.setSuccessDots() + } else { + mIndicatorDotsFirst!!.setErrorDots() + mIndicatorDotsFirst!!.startAnimation(shake) + } Handler().postDelayed({ mIndicatorDotsFirst!!.setDefaultDots() mPinLockView!!.resetPinLockView() @@ -48,7 +51,11 @@ class SampleActivity : AppCompatActivity() { val shake = AnimationUtils.loadAnimation(this@SampleActivity, R.anim.shake_wrong) mIndicatorDotsFirst!!.startAnimation(shake) // mIndicatorDotsFirst.setErrorDots(); - mIndicatorDotsFirst!!.setSuccessDots() + if (pin == "1111") { + mIndicatorDotsFirst!!.setSuccessDots() + } else { + mIndicatorDotsFirst!!.setErrorDots() + } Handler().postDelayed({ mIndicatorDotsFirst!!.setDefaultDots() mPinLockView!!.resetPinLockView() diff --git a/pinlockview/src/main/res/values/colors.xml b/pinlockview/src/main/res/values/colors.xml index f9ce4d85..02275c64 100644 --- a/pinlockview/src/main/res/values/colors.xml +++ b/pinlockview/src/main/res/values/colors.xml @@ -2,7 +2,7 @@ #fff #9E9C9C - #A50000 + #B40000 #50BD00 #333333 \ No newline at end of file