Skip to content

Instantly share code, notes, and snippets.

@KtodaZ
Last active October 28, 2016 05:27
Show Gist options
  • Save KtodaZ/45c039abfcb208055f33e72e538e1124 to your computer and use it in GitHub Desktop.
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
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