Last active
October 28, 2016 05:27
-
-
Save KtodaZ/45c039abfcb208055f33e72e538e1124 to your computer and use it in GitHub Desktop.
Custom validation and space/enter/comma button functionality (only for phone numbers) for android-chips library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void addPhoneRetvListeners() { | |
addPhoneRetvTextChangedListener(); | |
addPhoneRetvBackspaceListener(); | |
addPhoneRetvEnterKeyListener(); | |
} | |
/*Begin phoneRetvEditTextWatcher*/ | |
/**Add a listener to all the text changed in phoneRetv in order to detect errors upon user typing*/ | |
private void addPhoneRetvTextChangedListener() { | |
phoneRetv.addTextChangedListener(phoneRetvEditTextWatcher); | |
} | |
/** Watches phoneRetv and removes error text*/ | |
private final TextWatcher phoneRetvEditTextWatcher = new TextWatcher() { | |
public void beforeTextChanged(CharSequence s, int start, int count, int after) { | |
} | |
public void onTextChanged(CharSequence charactersPressed, int start, int before, int count) { | |
if (count == 1) { | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: Count is " + count + "charactersPressed: " + charactersPressed + "start: " + start + "before: " + before); | |
tryAddChipFromTextEntered(false); | |
} else { | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: Count is " + count); | |
} | |
} | |
public void afterTextChanged(Editable s) { | |
} | |
}; | |
/**Add onkeyListener to clear the error message once backspace is pressed*/ | |
private void addPhoneRetvBackspaceListener() { | |
phoneRetv.setOnKeyListener(new View.OnKeyListener() { | |
@Override | |
public boolean onKey(View v, int keyCode, KeyEvent event) { | |
if(keyCode == KEYCODE_DEL) { | |
Log.d(TAG, "PhoneRetv:OnKeyListener: Backspace pressed"); | |
clearPhoneRetvError(); | |
} | |
Log.d(TAG, "PhoneRetv:OnKeyListener: Key pressed - " + keyCode); | |
return false; | |
} | |
}); | |
} | |
/**Detect if enter key on keyboard is pressed*/ | |
private void addPhoneRetvEnterKeyListener() { | |
phoneRetv.setOnEditorActionListener(new TextView.OnEditorActionListener() { | |
@Override | |
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { | |
boolean result = false; | |
Log.d(TAG, "PhoneRetv:onEditorAction: actionId key pressed - " + actionId); | |
if (tryAddChipFromTextEntered(true)) { | |
result = true; | |
} else if (!isPhoneRetvInError()){ | |
// Go to next field | |
phoneRetv.clearFocus(); | |
messageContentEditText.requestFocus(); | |
} | |
return result; | |
} | |
}); | |
} | |
/**If user enters a phone number and clicks 'Enter', 'comma', or 'space', try to detect if | |
* that phone number is valid or if the phone number is a duplicate. If it's valid, add it | |
* as a manual chip entry.*/ | |
private boolean tryAddChipFromTextEntered(boolean enterKeyPressed) { | |
boolean isChipAddSuccessful = false; | |
final String chipLastPhone, fieldText; | |
String fieldLastPhone, lastTypedChar; | |
// Get PhoneRetv Field Data | |
fieldText = phoneRetv.getText().toString(); // Field text, including chips in a toString format | |
lastTypedChar = getLastCharOfString(fieldText); // Gets the last character of the "typed" text | |
fieldLastPhone = getFieldLastPhone(fieldText, lastTypedChar); // Get the supposed phone number the user entered | |
// Get chip data | |
updateChips(); | |
chipLastPhone = getLastPhoneFromChip(chips); | |
// Display some logging info | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: BEGINNING TO SEARCH =============================================================="); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: lastCharPhoneRetvToString pressed - '" + lastTypedChar + "'"); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: phoneRetvToString - '" + fieldText + "'"); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: phoneRetvToStringLastArrayIndex - '" + fieldLastPhone + "'"); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: Arrays.toString(chips) - '" + Arrays.toString(chips) + "'"); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: lastChipPhoneString - " + chipLastPhone); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: regex_strict.matcher(isPhoneValid(phoneRetvToStringLastArrayIndex) - " + isPhoneValid(fieldLastPhone)); | |
// Clear error upon user typing | |
clearPhoneRetvError(); | |
// Fix duplicates after 1.Selecting contact 2.backspacing 3.clicking "," | |
if (fieldText.endsWith(", ")) { | |
displayErrorIfDuplicate(chips); | |
} | |
// First, check if the conditions are correct to add a new phone number, then check if it's valid and add it | |
if (!doesPhoneEndWithBadKeys(fieldText) // Reject any endkeys that cause bugs | |
&& (enterKeyPressed || isLastCharValid(lastTypedChar)) // Check if valid endkey is pressed | |
&& !displayErrorIfDuplicate(chips) // Check for duplicates | |
&& isPhoneValid(fieldLastPhone)) { // Check if the entered number is valid | |
addNewChip(fieldLastPhone, fieldLastPhone); | |
displayErrorIfDuplicate(chips); | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: Created chip with phoneRetvToStringLastArrayIndex - '" + fieldLastPhone + " <------CHIP CREATED------"); | |
isChipAddSuccessful = true; | |
} | |
Log.d(TAG, "phoneRetvEditTextWatcher:onTextChanged: ENDING SEARCH ===================================================================="); | |
return isChipAddSuccessful; | |
} | |
private String getLastCharOfString(String str) { | |
if (str.length()>0) | |
return str.substring(str.length() - 1); | |
else return EMPTY_STRING; | |
} | |
/**Try to retrieve the phone number that the user entered*/ | |
private String getFieldLastPhone(String fieldText, String lastTypedChar) { | |
String[] fieldTextArray = getValidFieldTextArray(fieldText, lastTypedChar); | |
return fieldTextArray[fieldTextArray.length - 1].trim(); | |
} | |
/**Gets an array filled with "valid" information. It cleans or deletes invalid index's*/ | |
private String[] getValidFieldTextArray(String fieldText, String lastTypedChar){ | |
String[] fieldTextArray; | |
// Split phoneRetvToString by commas and spaces depending on what it ends with | |
if (lastTypedChar.equals(PHONERETV_CUSTOM_ENDKEYS[0])) { | |
fieldTextArray = fieldText.split(PHONERETV_CUSTOM_ENDKEYS[0]); | |
} else { | |
fieldTextArray = fieldText.split(PHONERETV_CUSTOM_ENDKEYS[0] + PHONERETV_CUSTOM_ENDKEYS[1]); | |
} | |
// Remove all non-numericals from array | |
for (int i =0; i < fieldTextArray.length; i++) { | |
fieldTextArray[i] = deleteAllNonNumbericals(fieldTextArray[i]); | |
} | |
// Trim last array index if last index is an empty string | |
if ((fieldTextArray[fieldTextArray.length - 1].trim().equals(EMPTY_STRING) | |
|| fieldTextArray[fieldTextArray.length - 1].trim().equals(",") ) | |
&& fieldTextArray.length > 1) { // fieldTextArray.length is needed to avoid Exception | |
ArrayList<String> fieldTextArrayList = new ArrayList<>(Arrays.asList(fieldTextArray)); | |
fieldTextArrayList.remove(fieldTextArray.length - 1); | |
//noinspection ToArrayCallWithZeroLengthArrayArgument | |
return fieldTextArrayList.toArray(new String[0]); | |
} else { | |
return fieldTextArray; | |
} | |
} | |
/**Replace all non numericals with an empty string*/ | |
private String deleteAllNonNumbericals(String fieldText) { | |
final String nonNumericalRegex = "[^0-9]"; | |
return fieldText.replaceAll(nonNumericalRegex,EMPTY_STRING); | |
} | |
/**Detects duplicates in a chips array. O(n^2) but it's a small array, so doesn't matter.*/ | |
private boolean displayErrorIfDuplicate(DrawableRecipientChip[] chips) { | |
final int arrayLength = chips.length; | |
String phones[] = new String[arrayLength]; | |
for (int i = 0; i < arrayLength; i++) { | |
// Replace all non-numericals with an empty string | |
phones[i] = deleteAllNonNumbericals(getPhoneNumbersFromChip(chips[i])); | |
// If phone is has a preceding "1", remove it | |
if (phones[i].startsWith("1")) phones[i] = phones[i].substring(1); | |
} | |
for (int i = 0; i < arrayLength; i++) { | |
for (int j = i + 1; j < arrayLength; j++) { | |
if (j != i && arePhoneNumbersDuplicate(phones[i], phones[j])) { | |
Log.e(TAG, "displayErrorIfDuplicate: " + | |
"Duplicates found for chipPhoneArray[j] - '" + phones[i] + "' " + | |
"chipPhoneArray[k] - '" + phones[j] + "' " + " <------DUPLICATES FOUND 1------"); | |
errorPhoneWrong(getString(R.string.AddMessage_PhoneRetv_DuplicatePhone)); | |
return true; | |
} | |
Log.d(TAG, "displayErrorIfDuplicate: " + | |
"Duplicates not found for chipPhoneArray[j] - '" + phones[i] + "' " + | |
"chipPhoneArray[k] - '" + phones[j] + "' " + " <------DUPLICATES NOT FOUND 1------"); | |
} | |
} | |
return false; | |
} | |
/**Detects if two phone numbers are duplicates*/ | |
private boolean arePhoneNumbersDuplicate(String phone1, String phone2) { | |
return !phone1.equals(EMPTY_STRING) && !phone2.equals(EMPTY_STRING) && phone2.equals(phone1); | |
} | |
/**Detect if the last key entered is a valid key (e.g. comma)*/ | |
private boolean doesPhoneEndWithBadKeys(String phone) { | |
for (String badKey : PHONERETV_CUSTOM_ENDKEYS_BAD) { | |
if (phone.endsWith(badKey)) return true; | |
} | |
return false; | |
} | |
/**Check if the last character is a valid endkey*/ | |
private boolean isLastCharValid(String lastChar) { | |
for (String endKey : PHONERETV_CUSTOM_ENDKEYS) if (lastChar.equalsIgnoreCase(endKey)) return true; | |
return false; | |
} | |
/**Check if the entered phone number is in a valid form*/ | |
private boolean isPhoneValid(String phone) { | |
final Pattern phone_regex_strict = Pattern.compile(PHONERETV_PHONE_REGEX_STRICT); | |
return phone_regex_strict.matcher(phone).matches(); | |
} | |
private String getLastPhoneFromChip(DrawableRecipientChip[] chips) { | |
if (chips.length > 0) | |
return getPhoneNumbersFromChip( chips[chips.length - 1].toString().trim() ); | |
else return null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment