diff --git a/README.md b/README.md
index 83bf370c..5d5ad95f 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ This library is available in **jCenter** which is the default Maven repository u
dependencies {
// other dependencies here
- compile 'com.andrognito.pinlockview:pinlockview:2.0.1'
+ implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
}
```
@@ -31,7 +31,7 @@ dependencies {
com.andrognito.pinlockview
pinlockview
- 2.0.1
+ 2.1.0
pom
```
@@ -164,7 +164,8 @@ Android & Backend Developer. Blogger. Designer. Fitness Enthusiast.
-
+
+
# License
diff --git a/app/build.gradle b/app/build.gradle
index a56194f5..de9556a1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 24
- buildToolsVersion "24.0.3"
+ compileSdkVersion 25
+ buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.andrognito.pinlockviewapp"
minSdkVersion 11
- targetSdkVersion 24
+ targetSdkVersion 25
versionCode 1
versionName "1.0"
}
@@ -22,6 +22,6 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:24.2.1'
+ compile 'com.android.support:appcompat-v7:25.3.1'
compile project(':pinlockview')
}
diff --git a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java
index 25d628b8..1e846109 100644
--- a/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java
+++ b/app/src/main/java/com/andrognito/pinlockviewapp/SampleActivity.java
@@ -1,7 +1,7 @@
package com.andrognito.pinlockviewapp;
+import android.graphics.Color;
import android.os.Bundle;
-import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Window;
@@ -9,10 +9,14 @@
import android.widget.ImageView;
import android.view.View;
import android.view.View.*;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
import com.andrognito.pinlockview.IndicatorDots;
+import com.andrognito.pinlockview.InputField;
import com.andrognito.pinlockview.PinLockListener;
import com.andrognito.pinlockview.PinLockView;
+import com.andrognito.pinlockview.SeparateDeleteButton;
public class SampleActivity extends AppCompatActivity {
@@ -20,13 +24,16 @@ public class SampleActivity extends AppCompatActivity {
private PinLockView mPinLockView;
private IndicatorDots mIndicatorDots;
+ private InputField mInputField;
+ private SeparateDeleteButton mSeparateDeleteButton;
private ImageView logo;
- private boolean isShowing = true;
+ private boolean isEnterButtonEnabled = true;
private PinLockListener mPinLockListener = new PinLockListener() {
@Override
public void onComplete(String pin) {
Log.d(TAG, "Pin complete: " + pin);
+ Toast.makeText(SampleActivity.this, "Pin complete: " + pin, Toast.LENGTH_SHORT).show();
}
@Override
@@ -49,28 +56,69 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_sample);
logo = (ImageView) findViewById(R.id.profile_image);
mPinLockView = (PinLockView) findViewById(R.id.pin_lock_view);
+ mInputField = (InputField) findViewById(R.id.input_field);
mIndicatorDots = (IndicatorDots) findViewById(R.id.indicator_dots);
+ mSeparateDeleteButton = (SeparateDeleteButton) findViewById(R.id.separate_delete_button);
+ mPinLockView.attachInputField(mInputField);
mPinLockView.attachIndicatorDots(mIndicatorDots);
+ mPinLockView.attachSeparateDeleteButton(mSeparateDeleteButton);
+
mPinLockView.setPinLockListener(mPinLockListener);
- //mPinLockView.setCustomKeySet(new int[]{2, 3, 1, 5, 9, 6, 7, 0, 8, 4});
- //mPinLockView.enableLayoutShuffling();
+ mPinLockView.setPinLength(6);
+ mPinLockView.setShowDeleteButton(false);
+ ((RelativeLayout.LayoutParams) mPinLockView.getLayoutParams()).addRule(RelativeLayout.BELOW, R.id.input_field);
+ mInputField.setVisibility(View.VISIBLE);
+ mInputField.requestFocus();
+
+ mSeparateDeleteButton.setShowSeparateDeleteButton(true);
+ mSeparateDeleteButton.setSeparateDeleteButtonColor(Color.TRANSPARENT);
+ mSeparateDeleteButton.setSeparateDeleteButtonPressedColor(Color.GRAY);
+ mSeparateDeleteButton.setImageResource(R.drawable.ic_keyboard_backspace);
- mPinLockView.setPinLength(4);
+ mPinLockView.setUseCustomEnterButtonImages(true);
+ mPinLockView.setEnterButtonEnabledDrawableId(R.drawable.ic_check_box);
+ mPinLockView.setEnterButtonDisabledDrawableId(R.drawable.ic_check_box_outline);
+ mPinLockView.setEnterButtonPressedDrawableId(R.drawable.ic_check_box);
+ mPinLockView.setDeleteButtonDrawable(getResources().getDrawable(R.drawable.ic_cheveron_left));
- mIndicatorDots.setIndicatorType(IndicatorDots.IndicatorType.FILL_WITH_ANIMATION);
+ mPinLockView.detachIndicatorDots();
+ mIndicatorDots.setVisibility(View.GONE);
+ mIndicatorDots.setIndicatorType(IndicatorDots.IndicatorType.FIXED);
logo.setOnClickListener(new OnClickListener() {
- public void onClick(View v)
- {
- if(isShowing) {
- mPinLockView.setVisibility(View.GONE);
- mIndicatorDots.setVisibility(View.GONE);
- isShowing = false;
- } else {
- mPinLockView.setVisibility(View.VISIBLE);
+ public void onClick(View v) {
+ if (isEnterButtonEnabled) {
+
+ isEnterButtonEnabled = false;
+ mPinLockView.setShowEnterButton(false);
+ mPinLockView.setSwapEnterDeleteButtons(false);
+ mPinLockView.setShowDeleteButton(true);
+ mSeparateDeleteButton.setShowSeparateDeleteButton(false);
+ mInputField.setVisibility(View.GONE);
mIndicatorDots.setVisibility(View.VISIBLE);
- isShowing = true;
+ ((RelativeLayout.LayoutParams) mPinLockView.getLayoutParams()).addRule(RelativeLayout.BELOW, R.id.indicator_dots);
+ mPinLockView.resetPinLockView();
+
+ mPinLockView.detachInputField();
+ mPinLockView.detachSeparateDeleteButton();
+ mPinLockView.attachIndicatorDots(mIndicatorDots);
+ } else{
+
+ isEnterButtonEnabled = true;
+ mPinLockView.setShowEnterButton(true);
+ mPinLockView.setSwapEnterDeleteButtons(true);
+ mPinLockView.setShowDeleteButton(false);
+ mSeparateDeleteButton.setShowSeparateDeleteButton(true);
+ mInputField.setVisibility(View.VISIBLE);
+ mIndicatorDots.setVisibility(View.GONE);
+ ((RelativeLayout.LayoutParams) mPinLockView.getLayoutParams()).addRule(RelativeLayout.BELOW, R.id.input_field);
+ mInputField.requestFocus();
+ mPinLockView.resetPinLockView();
+
+ mPinLockView.attachInputField(mInputField);
+ mPinLockView.attachSeparateDeleteButton(mSeparateDeleteButton);
+ mPinLockView.detachIndicatorDots();
}
}
});
diff --git a/app/src/main/res/drawable-hdpi/ic_check_box.png b/app/src/main/res/drawable-hdpi/ic_check_box.png
new file mode 100644
index 00000000..dfde503b
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_check_box.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_check_box_outline.png b/app/src/main/res/drawable-hdpi/ic_check_box_outline.png
new file mode 100644
index 00000000..ea0e7e63
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_check_box_outline.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_cheveron_left.png b/app/src/main/res/drawable-hdpi/ic_cheveron_left.png
new file mode 100644
index 00000000..fb87e635
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_cheveron_left.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_keyboard_backspace.png b/app/src/main/res/drawable-hdpi/ic_keyboard_backspace.png
new file mode 100644
index 00000000..8d7c3a7d
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_keyboard_backspace.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_check_box.png b/app/src/main/res/drawable-mdpi/ic_check_box.png
new file mode 100644
index 00000000..ad595bcc
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_check_box.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_check_box_outline.png b/app/src/main/res/drawable-mdpi/ic_check_box_outline.png
new file mode 100644
index 00000000..a7598b03
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_check_box_outline.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_cheveron_left.png b/app/src/main/res/drawable-mdpi/ic_cheveron_left.png
new file mode 100644
index 00000000..e301accb
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_cheveron_left.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_keyboard_backspace.png b/app/src/main/res/drawable-mdpi/ic_keyboard_backspace.png
new file mode 100644
index 00000000..81678c64
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_keyboard_backspace.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_check_box.png b/app/src/main/res/drawable-xhdpi/ic_check_box.png
new file mode 100644
index 00000000..b1bc4430
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_check_box.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_check_box_outline.png b/app/src/main/res/drawable-xhdpi/ic_check_box_outline.png
new file mode 100644
index 00000000..20ed7755
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_check_box_outline.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_cheveron_left.png b/app/src/main/res/drawable-xhdpi/ic_cheveron_left.png
new file mode 100644
index 00000000..764df638
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_cheveron_left.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_keyboard_backspace.png b/app/src/main/res/drawable-xhdpi/ic_keyboard_backspace.png
new file mode 100644
index 00000000..5abe5bcc
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_keyboard_backspace.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_check_box.png b/app/src/main/res/drawable-xxhdpi/ic_check_box.png
new file mode 100644
index 00000000..5529859e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_check_box.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_check_box_outline.png b/app/src/main/res/drawable-xxhdpi/ic_check_box_outline.png
new file mode 100644
index 00000000..8d34740c
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_check_box_outline.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_cheveron_left.png b/app/src/main/res/drawable-xxhdpi/ic_cheveron_left.png
new file mode 100644
index 00000000..e5f8c0db
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_cheveron_left.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_keyboard_backspace.png b/app/src/main/res/drawable-xxhdpi/ic_keyboard_backspace.png
new file mode 100644
index 00000000..58343f19
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_keyboard_backspace.png differ
diff --git a/app/src/main/res/layout/activity_sample.xml b/app/src/main/res/layout/activity_sample.xml
index 95b96595..a72f15df 100644
--- a/app/src/main/res/layout/activity_sample.xml
+++ b/app/src/main/res/layout/activity_sample.xml
@@ -15,6 +15,8 @@
android:layout_marginTop="104dp"
android:src="@drawable/img_no_avatar" />
+
+
+
+
+
+
+ app:keypadShowLetters="true"
+ app:keypadDeleteButtonColor="#E1BEE7"
+ app:keypadDefaultDeleteColor="false"
+ app:keypadDeleteButtonPressedColor="@color/white"
+ app:keypadShowEnterButton="true"
+ app:keypadSwapEnterDeleteButtons="true"
+ app:keypadEnterButtonColor="@android:color/transparent"
+ app:keypadEnterButtonDisabledColor="@android:color/transparent"
+ app:keypadEnterButtonPressedColor="@color/greyish"
+ app:indicatorType="fixed"
+ />
diff --git a/build.gradle b/build.gradle
index b249cff4..2976defb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.3'
+ classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
// NOTE: Do not place your application dependencies here; they belong
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 660db70a..568ab3c4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Mar 10 00:08:20 IST 2017
+#Tue Dec 12 09:32:28 EET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/pinlockview/build.gradle b/pinlockview/build.gradle
index 618feb4e..2fe6adbf 100644
--- a/pinlockview/build.gradle
+++ b/pinlockview/build.gradle
@@ -13,7 +13,7 @@ ext {
siteUrl = 'https://github.com/aritraroy/PinLockView'
gitUrl = 'https://github.com/aritraroy/PinLockView.git'
- libraryVersion = '2.0.1'
+ libraryVersion = '2.1.0'
developerId = 'aritraroy'
developerName = 'Aritra Roy'
@@ -27,13 +27,13 @@ ext {
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "25.0.3"
defaultConfig {
minSdkVersion 11
targetSdkVersion 25
- versionCode 4
- versionName "2.0.1"
+ versionCode 5
+ versionName "2.1.0"
}
buildTypes {
release {
@@ -46,8 +46,8 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:25.2.0'
- compile 'com.android.support:recyclerview-v7:25.2.0'
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'com.android.support:recyclerview-v7:25.3.1'
}
apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java b/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java
index d2fe486b..1e9f939a 100644
--- a/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/CustomizationOptionsBundle.java
@@ -5,11 +5,10 @@
/**
* 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 numberTextColor;
private int lettersTextColor;
private int deleteButtonColor;
@@ -29,6 +28,19 @@ public class CustomizationOptionsBundle {
private boolean useDeprecated;
private int deleteButtonPressesColor;
+ private boolean showEnterButton;
+ private int pinLength;
+ private boolean swapEnterDeleteButtons;
+
+ private int enterButtonColor;
+ private int enterButtonDisabledColor;
+ private int enterButtonPressesColor;
+ private boolean useCustomEnterButtomImages;
+ private int enterButtonEnabledDrawableId;
+ private int enterButtonDisabledDrawableId;
+ private int enterButtonPressedDrawableId;
+
+
public CustomizationOptionsBundle() {
}
@@ -176,4 +188,84 @@ public int getDeleteButtonPressesColor() {
public void setDeleteButtonPressesColor(int deleteButtonPressesColor) {
this.deleteButtonPressesColor = deleteButtonPressesColor;
}
+
+ public boolean isShowEnterButton() {
+ return showEnterButton;
+ }
+
+ public void setShowEnterButton(boolean showEnterButton) {
+ this.showEnterButton = showEnterButton;
+ }
+
+ public int getEnterButtonColor() {
+ return this.enterButtonColor;
+ }
+
+ public void setEnterButtonColor(int enterButtonColor) {
+ this.enterButtonColor = enterButtonColor;
+ }
+
+ public int getEnterButtonDisabledColor() {
+ return this.enterButtonDisabledColor;
+ }
+
+ public void setEnterButtonDisabledColor(int enterButtonDisabledColor) {
+ this.enterButtonDisabledColor = enterButtonDisabledColor;
+ }
+
+ public int getEnterButtonPressesColor() {
+ return this.enterButtonPressesColor;
+ }
+
+ public void setEnterButtonPressesColor(int enterButtonPressesColor) {
+ this.enterButtonPressesColor = enterButtonPressesColor;
+ }
+
+ public int getPinLength() {
+ return pinLength;
+ }
+
+ public void setPinLength(int pinLength) {
+ this.pinLength = pinLength;
+ }
+
+ public boolean isSwapEnterDeleteButtons() {
+ return swapEnterDeleteButtons;
+ }
+
+ public void setSwapEnterDeleteButtons(boolean swapEnterDeleteButtons) {
+ this.swapEnterDeleteButtons = swapEnterDeleteButtons;
+ }
+
+ public boolean isUseCustomEnterButtonImages() {
+ return useCustomEnterButtomImages;
+ }
+
+ public void setUseCustomEnterButtonImages(boolean useCustomEnterButtomImages) {
+ this.useCustomEnterButtomImages = useCustomEnterButtomImages;
+ }
+
+ public int getEnterButtonEnabledDrawableId() {
+ return enterButtonEnabledDrawableId;
+ }
+
+ public void setEnterButtonEnabledDrawableId(int enterButtonEnabledDrawableId) {
+ this.enterButtonEnabledDrawableId = enterButtonEnabledDrawableId;
+ }
+
+ public int getEnterButtonDisabledDrawableId() {
+ return enterButtonDisabledDrawableId;
+ }
+
+ public void setEnterButtonDisabledDrawableId(int enterButtonDisabledDrawableId) {
+ this.enterButtonDisabledDrawableId = enterButtonDisabledDrawableId;
+ }
+
+ public int getEnterButtonPressedDrawableId() {
+ return enterButtonPressedDrawableId;
+ }
+
+ public void setEnterButtonPressedDrawableId(int enterButtonPressedDrawableId) {
+ this.enterButtonPressedDrawableId = enterButtonPressedDrawableId;
+ }
}
diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java
index c8cea3d9..b332d4de 100644
--- a/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/IndicatorDots.java
@@ -4,6 +4,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.IntDef;
+import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -70,6 +71,7 @@ public IndicatorDots(Context context, AttributeSet attrs, int defStyleAttr) {
}
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);
diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/InputField.java b/pinlockview/src/main/java/com/andrognito/pinlockview/InputField.java
new file mode 100644
index 00000000..87e7068b
--- /dev/null
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/InputField.java
@@ -0,0 +1,178 @@
+package com.andrognito.pinlockview;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Handler;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.AppCompatEditText;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+public class InputField extends AppCompatEditText {
+
+ public InputField(Context context) {
+ super(context);
+
+ initView(context);
+ }
+
+ public InputField(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ initView(context);
+ }
+
+ public InputField(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ initView(context);
+ }
+
+ private void initView(Context context) {
+ ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR);
+
+ disableKeyboard(context);
+ setupPasswordDots();
+ }
+
+ private void disableKeyboard(Context context) {
+ setCursorVisible(true);
+ ((Activity) context).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
+ setShowSoftInputOnFocus(false);
+ setTextIsSelectable(true);
+ setInputType(InputType.TYPE_NULL);
+ setKeyListener(null);
+ setRawInputType(InputType.TYPE_CLASS_TEXT);
+ setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ /* do nothing */
+ }
+ });
+ setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ /* do nothing */
+ return true;
+ }
+ });
+ setOnKeyListener(new OnKeyListener() {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ /* do nothing */
+ return true;
+ }
+ });
+ setOnEditorActionListener(new OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ /* do nothing */
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return true;
+ }
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return true;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return true;
+ }
+
+ private void setupPasswordDots() {
+ TextWatcher pinWatcher = new TextWatcher() {
+
+ private Handler pinHandler = new Handler();
+
+ int oldLength = 0;
+ boolean editing = false;
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (editing) return; // Do nothing if editing field within the watcher, to prevent infinite loops
+
+ pinHandler.removeCallbacksAndMessages(null);
+
+ Runnable hideText = new Runnable() {
+ @Override
+ public void run() {
+ editing = true;
+ InputField.this.setText(hideString(InputField.this.getText().toString()));
+ InputField.this.setSelection(InputField.this.getText().length());
+ editing = false;
+ }
+ };
+
+ if (oldLength < s.toString().length()) { // Briefly display last digit if PIN increases
+ oldLength = s.length();
+
+ editing = true;
+ InputField.this.setText(almostHideString(InputField.this.getText().toString()));
+ InputField.this.setSelection(InputField.this.getText().length());
+ editing = false;
+
+ pinHandler.postDelayed(hideText, 1500);
+ } else { // Otherwise just hide PIN if deleting
+ oldLength = s.length();
+
+ hideText.run();
+ }
+ }
+
+ };
+
+ this.addTextChangedListener(pinWatcher);
+ }
+
+ private String almostHideString(String s) {
+ if (s == null || s.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < s.length() - 1; ++i) {
+ stringBuilder.append(DOT);
+ }
+ stringBuilder.append(s.charAt(s.length() - 1));
+
+ return stringBuilder.toString();
+ }
+
+ private String hideString(String s) {
+ if (s == null || s.isEmpty()) {
+ return "";
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < s.length(); ++i) {
+ stringBuilder.append(DOT);
+ }
+
+ return stringBuilder.toString();
+ }
+
+ private static char DOT = '\u2022';
+}
diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java b/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java
new file mode 100644
index 00000000..eac00a54
--- /dev/null
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/LTRGridLayoutManager.java
@@ -0,0 +1,31 @@
+package com.andrognito.pinlockview;
+
+import android.content.Context;
+import android.support.v7.widget.GridLayoutManager;
+import android.util.AttributeSet;
+
+/**
+ * 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/PinLockAdapter.java b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java
index c90de0d5..57b10089 100644
--- a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockAdapter.java
@@ -1,8 +1,10 @@
package com.andrognito.pinlockview;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.Typeface;
import android.os.Build;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
@@ -10,11 +12,10 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.graphics.Typeface;
/**
* Created by aritraroy on 31/05/16.
@@ -23,11 +24,18 @@ public class PinLockAdapter extends RecyclerView.Adapter 0) {
+ holder.mDeleteButton.setEnabled(true);
holder.mDeleteButton.setVisibility(View.VISIBLE);
if (mCustomizationOptionsBundle.getDeleteButtonDrawable() != null) {
holder.mButtonImage.setImageDrawable(mCustomizationOptionsBundle.getDeleteButtonDrawable());
@@ -189,8 +204,49 @@ private void configureDeleteButtonHolder(DeleteViewHolder holder) {
mCustomizationOptionsBundle.getButtonSize());
holder.mDeleteButton.setLayoutParams(params);
} else {
+ holder.mDeleteButton.setEnabled(false);
holder.mDeleteButton.setVisibility(View.GONE);
}
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ mCustomizationOptionsBundle.getButtonSize(),
+ mCustomizationOptionsBundle.getButtonSize());
+ holder.mDeleteButton.setLayoutParams(params);
+ }
+ }
+
+ private void configureEnterButtonHolder(EnterViewHolder holder) {
+ if (holder != null) {
+ if (mCustomizationOptionsBundle.isShowEnterButton()) {
+ // Set Enable of Enter Button
+ if (mPinLength >= mCustomizationOptionsBundle.getPinLength()) {
+ holder.mEnterButton.setEnabled(true);
+ if (mCustomizationOptionsBundle.isUseCustomEnterButtonImages()) {
+ holder.mEnterButton.setImageResource(mCustomizationOptionsBundle.getEnterButtonEnabledDrawableId());
+ }
+ holder.mEnterButton.setColorFilter(mCustomizationOptionsBundle.getEnterButtonColor(),
+ PorterDuff.Mode.SRC_ATOP);
+ } else {
+ holder.mEnterButton.setEnabled(false);
+ if (mCustomizationOptionsBundle.isUseCustomEnterButtonImages()) {
+ holder.mEnterButton.setImageResource(mCustomizationOptionsBundle.getEnterButtonDisabledDrawableId());
+ }
+ holder.mEnterButton.setColorFilter(mCustomizationOptionsBundle.getEnterButtonDisabledColor(),
+ PorterDuff.Mode.SRC_ATOP);
+ }
+
+ // Set Visibility of Enter Button
+ if (holder.mEnterButton.getVisibility() != View.VISIBLE) {
+ holder.mEnterButton.setVisibility(View.VISIBLE);
+ }
+ } else {
+ holder.mEnterButton.setEnabled(false);
+ holder.mEnterButton.setVisibility(View.GONE);
+ }
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ mCustomizationOptionsBundle.getButtonSize(),
+ mCustomizationOptionsBundle.getButtonSize());
+ holder.mEnterButton.setLayoutParams(params);
}
}
@@ -201,7 +257,10 @@ public int getItemCount() {
@Override
public int getItemViewType(int position) {
- if (position == getItemCount() - 1) {
+ if (position == getEnterButtonPosition()) {
+ return VIEW_TYPE_ENTER;
+ }
+ if (position == getDeleteButtonPosition()) {
return VIEW_TYPE_DELETE;
}
return VIEW_TYPE_NUMBER;
@@ -253,12 +312,34 @@ public void setOnDeleteClickListener(OnDeleteClickListener onDeleteClickListener
this.mOnDeleteClickListener = onDeleteClickListener;
}
+ public void setOnEnterClickListener(OnEnterClickListener onEnterClickListener) {
+ this.mOnEnterClickListener = onEnterClickListener;
+ }
+
public CustomizationOptionsBundle getCustomizationOptions() {
return mCustomizationOptionsBundle;
}
public void setCustomizationOptions(CustomizationOptionsBundle customizationOptionsBundle) {
this.mCustomizationOptionsBundle = customizationOptionsBundle;
+ setEnterButtonPosition(mCustomizationOptionsBundle.isSwapEnterDeleteButtons() ? 11 : 9);
+ setDeleteButtonPosition(mCustomizationOptionsBundle.isSwapEnterDeleteButtons() ? 9 : 11);
+ }
+
+ public int getEnterButtonPosition() {
+ return enterButtonPosition;
+ }
+
+ public void setEnterButtonPosition(int enterButtonPosition) {
+ this.enterButtonPosition = enterButtonPosition;
+ }
+
+ public int getDeleteButtonPosition() {
+ return deleteButtonPosition;
+ }
+
+ public void setDeleteButtonPosition(int deleteButtonPosition) {
+ this.deleteButtonPosition = deleteButtonPosition;
}
public class NumberViewHolder extends RecyclerView.ViewHolder {
@@ -286,64 +367,120 @@ public class DeleteViewHolder extends RecyclerView.ViewHolder {
LinearLayout mDeleteButton;
ImageView mButtonImage;
+ @SuppressLint("ClickableViewAccessibility")
public DeleteViewHolder(final View itemView) {
super(itemView);
mDeleteButton = (LinearLayout) itemView.findViewById(R.id.button);
mButtonImage = (ImageView) 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.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;
- mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (mOnDeleteClickListener != null) {
- mOnDeleteClickListener.onDeleteLongClicked();
+ @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) {
+ if (mCustomizationOptionsBundle.getDeleteButtonDefault()) {
+ mButtonImage.clearColorFilter();
+ } else {
+ mButtonImage.setColorFilter(mCustomizationOptionsBundle.getDeleteButtonColor(),
+ PorterDuff.Mode.SRC_ATOP);
}
- return true;
}
- });
+ if (leftButtonArea(v, event)) {
+ if (mCustomizationOptionsBundle.getDeleteButtonDefault()) {
+ mButtonImage.clearColorFilter();
+ } else {
+ mButtonImage.setColorFilter(mCustomizationOptionsBundle.getDeleteButtonColor(),
+ PorterDuff.Mode.SRC_ATOP);
+ }
+ }
+ return false;
+ }
+
+ private boolean leftButtonArea(View v, MotionEvent event) {
+ return rect != null && !rect.contains(v.getLeft() + (int) event.getX(),
+ v.getTop() + (int) event.getY());
+ }
+ });
+ }
+ }
+
+ public class EnterViewHolder extends RecyclerView.ViewHolder {
+ ImageButton mEnterButton;
+
+ @SuppressLint("ClickableViewAccessibility")
+ public EnterViewHolder(final View itemView) {
+ super(itemView);
+ mEnterButton = (ImageButton) itemView.findViewById(R.id.button);
+
+ mEnterButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnEnterClickListener != null) {
+ mOnEnterClickListener.onEnterClicked();
+ }
+ }
+ });
- mDeleteButton.setOnTouchListener(new View.OnTouchListener() {
- private Rect rect;
+ mEnterButton.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());
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mCustomizationOptionsBundle.isUseCustomEnterButtonImages()) {
+ mEnterButton.setImageResource(mCustomizationOptionsBundle.getEnterButtonPressedDrawableId());
}
- if (event.getAction() == MotionEvent.ACTION_UP) {
- if (mCustomizationOptionsBundle.getDeleteButtonDefault()) {
- mButtonImage.clearColorFilter();
- } else {
- mButtonImage.setColorFilter(mCustomizationOptionsBundle.getDeleteButtonColor(),
- PorterDuff.Mode.SRC_ATOP);
- }
+ mEnterButton.setColorFilter(mCustomizationOptionsBundle.getEnterButtonPressesColor(),
+ PorterDuff.Mode.SRC_ATOP);
+ rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ }
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (mCustomizationOptionsBundle.isUseCustomEnterButtonImages()) {
+ mEnterButton.setImageResource(mCustomizationOptionsBundle.getEnterButtonEnabledDrawableId());
}
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- if (!rect.contains(v.getLeft() + (int) event.getX(),
- v.getTop() + (int) event.getY())) {
- if (mCustomizationOptionsBundle.getDeleteButtonDefault()) {
- mButtonImage.clearColorFilter();
- } else {
- mButtonImage.setColorFilter(mCustomizationOptionsBundle.getDeleteButtonColor(),
- PorterDuff.Mode.SRC_ATOP);
- }
- }
+ mEnterButton.setColorFilter(mCustomizationOptionsBundle.getEnterButtonColor(),
+ PorterDuff.Mode.SRC_ATOP);
+ }
+ if (leftButtonArea(v, event)) {
+ if (mCustomizationOptionsBundle.isUseCustomEnterButtonImages()) {
+ mEnterButton.setImageResource(mCustomizationOptionsBundle.getEnterButtonEnabledDrawableId());
}
- return false;
+ mEnterButton.setColorFilter(mCustomizationOptionsBundle.getEnterButtonColor(),
+ PorterDuff.Mode.SRC_ATOP);
}
- });
- }
+ return false;
+ }
+
+ private boolean leftButtonArea(View v, MotionEvent event) {
+ return rect != null && !rect.contains(v.getLeft() + (int) event.getX(),
+ v.getTop() + (int) event.getY());
+ }
+ });
}
}
@@ -356,4 +493,8 @@ public interface OnDeleteClickListener {
void onDeleteLongClicked();
}
+
+ public interface OnEnterClickListener {
+ void onEnterClicked();
+ }
}
diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java
index 816d10ca..553add1f 100644
--- a/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/PinLockView.java
@@ -2,11 +2,12 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
-import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
+import android.view.View;
/**
* Represents a numeric lock view which can used to taken numbers as input.
@@ -33,7 +34,20 @@ public class PinLockView extends RecyclerView {
private boolean mDeleteButtonDefault;
private boolean mDeprecatedColorOptions;
+ private boolean mShowEnterButton;
+ private boolean mSwapEnterDeleteButtons;
+
+ private int mEnterButtonColor;
+ private int mEnterButtonDisabledColor;
+ private int mEnterButtonPressedColor;
+
+ private boolean mUseCustomEnterButtonImages;
+ private int mEnterButtonEnabledDrawableId;
+ private int mEnterButtonDisabledDrawableId;
+
private IndicatorDots mIndicatorDots;
+ private InputField mInputField;
+ private SeparateDeleteButton mSeparateDeleteButton;
private PinLockAdapter mAdapter;
private PinLockListener mPinLockListener;
private CustomizationOptionsBundle mCustomizationOptionsBundle;
@@ -49,34 +63,33 @@ public void onNumberClicked(int keyValue) {
if (isIndicatorDotsAttached()) {
mIndicatorDots.updateDot(mPin.length());
}
+ if (isInputFieldAttached()) {
+ mInputField.setText(mPin);
+ }
if (mPin.length() == 1) {
mAdapter.setPinLength(mPin.length());
- mAdapter.notifyItemChanged(mAdapter.getItemCount() - 1);
+ mAdapter.notifyItemChanged(mAdapter.getDeleteButtonPosition());
+ if (mSeparateDeleteButton != null && mSeparateDeleteButton.isShowSeparateDeleteButton()) {
+ mSeparateDeleteButton.setVisibility(View.VISIBLE);
+ }
+ }
+
+ if (mPin.length() == mPinLength) {
+ mAdapter.setPinLength(mPin.length());
+ mAdapter.notifyItemChanged(mAdapter.getEnterButtonPosition());
}
if (mPinLockListener != null) {
- if (mPin.length() == mPinLength) {
+ if (mPin.length() == mPinLength && !mShowEnterButton) {
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) {
+ if (mPinLockListener != null) {
+ if (!mShowEnterButton) {
mPinLockListener.onComplete(mPin);
}
}
@@ -94,10 +107,21 @@ public void onDeleteClicked() {
if (isIndicatorDotsAttached()) {
mIndicatorDots.updateDot(mPin.length());
}
+ if (isInputFieldAttached()) {
+ mInputField.setText(mPin);
+ }
if (mPin.length() == 0) {
mAdapter.setPinLength(mPin.length());
- mAdapter.notifyItemChanged(mAdapter.getItemCount() - 1);
+ mAdapter.notifyItemChanged(mAdapter.getDeleteButtonPosition());
+ if (mSeparateDeleteButton != null) {
+ mSeparateDeleteButton.setVisibility(View.GONE);
+ }
+ }
+
+ if (mPin.length() == mPinLength - 1) {
+ mAdapter.setPinLength(mPin.length());
+ mAdapter.notifyItemChanged(mAdapter.getEnterButtonPosition());
}
if (mPinLockListener != null) {
@@ -124,6 +148,16 @@ public void onDeleteLongClicked() {
}
};
+ private PinLockAdapter.OnEnterClickListener mOnEnterClickListener
+ = new PinLockAdapter.OnEnterClickListener() {
+ @Override
+ public void onEnterClicked() {
+ if (mPin.length() >= mPinLength) {
+ mPinLockListener.onComplete(mPin);
+ }
+ }
+ };
+
public PinLockView(Context context) {
super(context);
init(null, 0);
@@ -165,6 +199,15 @@ private void init(AttributeSet attributeSet, int defStyle) {
mDeprecatedColorOptions = typedArray.getBoolean(R.styleable.PinLockView_keypadUseDeprecatedColorOptions, true);
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));
+ mShowEnterButton = typedArray.getBoolean(R.styleable.PinLockView_keypadShowEnterButton, false);
+ if (mShowEnterButton) {
+ mShowDeleteButton = true;
+ }
+ mSwapEnterDeleteButtons = typedArray.getBoolean(R.styleable.PinLockView_keypadSwapEnterDeleteButtons, false);
+
+ mEnterButtonColor = typedArray.getColor(R.styleable.PinLockView_keypadEnterButtonColor, ResourceUtils.getColor(getContext(), R.color.white));
+ mEnterButtonDisabledColor = typedArray.getColor(R.styleable.PinLockView_keypadEnterButtonDisabledColor, ResourceUtils.getColor(getContext(), R.color.greyish));
+ mEnterButtonPressedColor = typedArray.getColor(R.styleable.PinLockView_keypadEnterButtonPressedColor, ResourceUtils.getColor(getContext(), R.color.greyish));
} finally {
typedArray.recycle();
}
@@ -189,15 +232,25 @@ private void init(AttributeSet attributeSet, int defStyle) {
mCustomizationOptionsBundle.setDeleteButtonDefault(mDeleteButtonDefault);
mCustomizationOptionsBundle.setUseDeprecated(mDeprecatedColorOptions);
+ mCustomizationOptionsBundle.setShowEnterButton(mShowEnterButton);
+ mCustomizationOptionsBundle.setPinLength(mPinLength);
+ mCustomizationOptionsBundle.setSwapEnterDeleteButtons(mSwapEnterDeleteButtons);
+
+ mCustomizationOptionsBundle.setEnterButtonColor(mEnterButtonColor);
+ mCustomizationOptionsBundle.setEnterButtonDisabledColor(mEnterButtonDisabledColor);
+ mCustomizationOptionsBundle.setEnterButtonPressesColor(mEnterButtonPressedColor);
initView();
}
private void initView() {
- setLayoutManager(new GridLayoutManager(getContext(), 3));
+ setLayoutManager(new LTRGridLayoutManager(getContext(), 3));
mAdapter = new PinLockAdapter(getContext());
mAdapter.setOnItemClickListener(mOnNumberClickListener);
mAdapter.setOnDeleteClickListener(mOnDeleteClickListener);
+
+ mAdapter.setOnEnterClickListener(mOnEnterClickListener);
+
mAdapter.setCustomizationOptions(mCustomizationOptionsBundle);
setAdapter(mAdapter);
@@ -230,10 +283,14 @@ public int getPinLength() {
*/
public void setPinLength(int pinLength) {
this.mPinLength = pinLength;
+ mCustomizationOptionsBundle.setPinLength(mPinLength);
if (isIndicatorDotsAttached()) {
mIndicatorDots.setPinLength(pinLength);
}
+ if (isInputFieldAttached()) {
+ mInputField.setText(mPin);
+ }
}
/**
@@ -574,6 +631,7 @@ public boolean isShowDeleteButton() {
public void setShowDeleteButton(boolean showDeleteButton) {
this.mShowDeleteButton = showDeleteButton;
mCustomizationOptionsBundle.setShowDeleteButton(showDeleteButton);
+ mAdapter.notifyItemChanged(mAdapter.getDeleteButtonPosition());
mAdapter.notifyDataSetChanged();
}
@@ -597,6 +655,29 @@ public void setDeleteButtonPressedColor(int deleteButtonPressedColor) {
mAdapter.notifyDataSetChanged();
}
+ public boolean isShowEnterButton() {
+ return mShowEnterButton;
+ }
+
+ public void setShowEnterButton(boolean showEnterButton) {
+ this.mShowEnterButton = showEnterButton;
+ mCustomizationOptionsBundle.setShowEnterButton(showEnterButton);
+ mAdapter.notifyItemChanged(mAdapter.getEnterButtonPosition());
+ mAdapter.notifyDataSetChanged();
+ }
+
+ public boolean isSwapEnterDeleteButtons() {
+ return mSwapEnterDeleteButtons;
+ }
+
+ public void setSwapEnterDeleteButtons(boolean swapEnterDeleteButtons) {
+ this.mSwapEnterDeleteButtons = swapEnterDeleteButtons;
+ mCustomizationOptionsBundle.setSwapEnterDeleteButtons(swapEnterDeleteButtons);
+ mAdapter.setEnterButtonPosition(mCustomizationOptionsBundle.isSwapEnterDeleteButtons() ? 11 : 9);
+ mAdapter.setDeleteButtonPosition(mCustomizationOptionsBundle.isSwapEnterDeleteButtons() ? 9 : 11);
+ mAdapter.notifyDataSetChanged();
+ }
+
public int[] getCustomKeySet() {
@@ -632,11 +713,20 @@ public void resetPinLockView() {
clearInternalPin();
mAdapter.setPinLength(mPin.length());
- mAdapter.notifyItemChanged(mAdapter.getItemCount() - 1);
+ mAdapter.notifyItemChanged(mAdapter.getEnterButtonPosition());
+ mAdapter.notifyItemChanged(mAdapter.getDeleteButtonPosition());
if (mIndicatorDots != null) {
mIndicatorDots.updateDot(mPin.length());
}
+ if (mInputField != null) {
+ mInputField.setText("");
+ }
+ if (mSeparateDeleteButton != null) {
+ mSeparateDeleteButton.setVisibility(View.GONE);
+ mSeparateDeleteButton.setColorFilter(mSeparateDeleteButton.getSeparateDeleteButtonColor(),
+ PorterDuff.Mode.SRC_ATOP);
+ }
}
/**
@@ -656,4 +746,82 @@ public boolean isIndicatorDotsAttached() {
public void attachIndicatorDots(IndicatorDots mIndicatorDots) {
this.mIndicatorDots = mIndicatorDots;
}
+
+ public void detachIndicatorDots() {
+ this.mIndicatorDots = null;
+ }
+
+ /**
+ * Returns true if {@link SeparateDeleteButton} is attached to {@link PinLockView}
+ *
+ * @return true if attached, false otherwise
+ */
+ public boolean isSeparateDeleteButtonAttached() {
+ return mSeparateDeleteButton != null;
+ }
+
+ /**
+ * Attaches {@link SeparateDeleteButton} to {@link PinLockView}
+ *
+ * @param separateDeleteButton the SeparateDeleteButton to attach
+ */
+ public void attachSeparateDeleteButton(SeparateDeleteButton separateDeleteButton) {
+ this.mSeparateDeleteButton = separateDeleteButton;
+ this.mSeparateDeleteButton.setOnDeleteClickListener(mOnDeleteClickListener);
+ if (mPin.length() == 0) {
+ this.mSeparateDeleteButton.setVisibility(View.GONE);
+ } else {
+ this.mSeparateDeleteButton.setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void detachSeparateDeleteButton() {
+ this.mSeparateDeleteButton = null;
+ }
+
+ /**
+ * Returns true if {@link InputField} is attached to {@link PinLockView}
+ *
+ * @return true if attached, false otherwise
+ */
+ public boolean isInputFieldAttached() {
+ return mInputField != null;
+ }
+
+ /**
+ * Attaches {@link InputField} to {@link PinLockView}
+ *
+ * @param inputField the InputField to attach
+ */
+ public void attachInputField(InputField inputField) {
+ this.mInputField = inputField;
+ }
+
+ public void detachInputField() {
+ this.mInputField = null;
+ }
+
+ public void setUseCustomEnterButtonImages(boolean useCustomEnterButtonImages) {
+ this.mUseCustomEnterButtonImages = useCustomEnterButtonImages;
+ mCustomizationOptionsBundle.setUseCustomEnterButtonImages(useCustomEnterButtonImages);
+ mAdapter.notifyDataSetChanged();
+ }
+
+ public void setEnterButtonEnabledDrawableId(int id) {
+ this.mEnterButtonEnabledDrawableId = id;
+ mCustomizationOptionsBundle.setEnterButtonEnabledDrawableId(id);
+ mAdapter.notifyDataSetChanged();
+ }
+
+ public void setEnterButtonDisabledDrawableId(int id) {
+ this.mEnterButtonEnabledDrawableId = id;
+ mCustomizationOptionsBundle.setEnterButtonDisabledDrawableId(id);
+ mAdapter.notifyDataSetChanged();
+ }
+
+ public void setEnterButtonPressedDrawableId(int id) {
+ this.mEnterButtonEnabledDrawableId = id;
+ mCustomizationOptionsBundle.setEnterButtonPressedDrawableId(id);
+ mAdapter.notifyDataSetChanged();
+ }
}
diff --git a/pinlockview/src/main/java/com/andrognito/pinlockview/SeparateDeleteButton.java b/pinlockview/src/main/java/com/andrognito/pinlockview/SeparateDeleteButton.java
new file mode 100644
index 00000000..dca9eaee
--- /dev/null
+++ b/pinlockview/src/main/java/com/andrognito/pinlockview/SeparateDeleteButton.java
@@ -0,0 +1,132 @@
+package com.andrognito.pinlockview;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.AppCompatImageButton;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+@SuppressLint("ClickableViewAccessibility")
+public class SeparateDeleteButton extends AppCompatImageButton {
+
+ private PinLockAdapter.OnDeleteClickListener mOnDeleteClickListener;
+
+ private int mSeparateDeleteButtonColor;
+ private int mSeparateDeleteButtonPressedColor;
+ private boolean mShowSeparateDeleteButton = true;
+
+ public SeparateDeleteButton(Context context) {
+ super(context);
+ initView(context, null);
+ }
+
+ public SeparateDeleteButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initView(context, attrs);
+ }
+
+ public SeparateDeleteButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context, attrs);
+ }
+
+ public void initView(Context context, AttributeSet attrs) {
+ TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.PinLockView);
+
+ try {
+ mSeparateDeleteButtonColor = typedArray.getColor(R.styleable.PinLockView_separateDeleteButtonColor, ResourceUtils.getColor(getContext(), R.color.white));
+ mSeparateDeleteButtonPressedColor = typedArray.getColor(R.styleable.PinLockView_separateDeleteButtonPressedColor, ResourceUtils.getColor(getContext(), R.color.greyish));
+ } finally {
+ typedArray.recycle();
+ }
+
+ ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR);
+
+ setImageResource(R.drawable.ic_backspace);
+ setBackgroundColor(Color.TRANSPARENT);
+ setScaleType(ScaleType.FIT_CENTER);
+ setColorFilter(getSeparateDeleteButtonColor(), PorterDuff.Mode.SRC_ATOP);
+
+ setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnDeleteClickListener != null) {
+ mOnDeleteClickListener.onDeleteClicked();
+ }
+ }
+ });
+
+ setOnLongClickListener(new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mOnDeleteClickListener != null) {
+ mOnDeleteClickListener.onDeleteLongClicked();
+ }
+ return true;
+ }
+ });
+
+ setOnTouchListener(new OnTouchListener() {
+ private Rect rect;
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ SeparateDeleteButton.this.setColorFilter(
+ getSeparateDeleteButtonPressedColor(), PorterDuff.Mode.SRC_ATOP);
+ rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ }
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ SeparateDeleteButton.this.setColorFilter(
+ getSeparateDeleteButtonColor(), PorterDuff.Mode.SRC_ATOP);
+ }
+ if (leftButtonArea(v, event)) {
+ SeparateDeleteButton.this.setColorFilter(
+ getSeparateDeleteButtonColor(), PorterDuff.Mode.SRC_ATOP);
+ }
+ return false;
+ }
+
+ private boolean leftButtonArea(View v, MotionEvent event) {
+ return rect != null && !rect.contains(v.getLeft() + (int) event.getX(),
+ v.getTop() + (int) event.getY());
+ }
+ });
+
+ }
+
+ public void setOnDeleteClickListener(PinLockAdapter.OnDeleteClickListener mOnDeleteClickListener) {
+ this.mOnDeleteClickListener = mOnDeleteClickListener;
+ }
+
+ public int getSeparateDeleteButtonColor() {
+ return mSeparateDeleteButtonColor;
+ }
+
+ public void setSeparateDeleteButtonColor(int mSeparateDeleteButtonColor) {
+ this.mSeparateDeleteButtonColor = mSeparateDeleteButtonColor;
+ setColorFilter(getSeparateDeleteButtonColor(), PorterDuff.Mode.SRC_ATOP);
+ }
+
+ public int getSeparateDeleteButtonPressedColor() {
+ return mSeparateDeleteButtonPressedColor;
+ }
+
+ public void setSeparateDeleteButtonPressedColor(int mSeparateDeleteButtonPressedColor) {
+ this.mSeparateDeleteButtonPressedColor = mSeparateDeleteButtonPressedColor;
+ }
+
+ public boolean isShowSeparateDeleteButton() {
+ return mShowSeparateDeleteButton;
+ }
+
+ public void setShowSeparateDeleteButton(boolean mShowSeparateDeleteButton) {
+ this.mShowSeparateDeleteButton = mShowSeparateDeleteButton;
+ }
+}
diff --git a/pinlockview/src/main/res/drawable/ic_check_circle.png b/pinlockview/src/main/res/drawable/ic_check_circle.png
new file mode 100644
index 00000000..f88c7828
Binary files /dev/null and b/pinlockview/src/main/res/drawable/ic_check_circle.png differ
diff --git a/pinlockview/src/main/res/layout/layout_enter_item.xml b/pinlockview/src/main/res/layout/layout_enter_item.xml
new file mode 100644
index 00000000..82dd0aa2
--- /dev/null
+++ b/pinlockview/src/main/res/layout/layout_enter_item.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pinlockview/src/main/res/values/attrs.xml b/pinlockview/src/main/res/values/attrs.xml
index 854a761c..bc7311fe 100644
--- a/pinlockview/src/main/res/values/attrs.xml
+++ b/pinlockview/src/main/res/values/attrs.xml
@@ -23,6 +23,12 @@
+
+
+
+
+
+
@@ -33,6 +39,9 @@
+
+
+
\ No newline at end of file