Last active
August 3, 2020 22:55
-
-
Save cjae/260c456a3ef6104c34f219ec37f82a5a to your computer and use it in GitHub Desktop.
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
<?xml version="1.0" encoding="utf-8"?> | |
<androidx.core.widget.NestedScrollView | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:scrollbars="none" | |
android:background="@color/app_white" | |
tools:context=".features.cardpayment.CardPaymentActivity"> | |
<androidx.constraintlayout.widget.ConstraintLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<FrameLayout | |
android:id="@+id/back_button" | |
android:layout_width="?attr/actionBarSize" | |
android:layout_height="?attr/actionBarSize" | |
android:background="?selectableItemBackgroundBorderless" | |
android:clickable="true" | |
android:focusable="true" | |
app:layout_constraintTop_toTopOf="parent" | |
app:layout_constraintStart_toStartOf="parent"> | |
<androidx.appcompat.widget.AppCompatImageView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_gravity="center" | |
app:srcCompat="@drawable/round_chevron_left_24" | |
app:tint="@color/primary_text_color" /> | |
</FrameLayout> | |
<androidx.appcompat.widget.AppCompatTextView | |
android:id="@+id/flightModeView" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="@string/payment" | |
android:textSize="@dimen/_16ssp" | |
fontPath="fonts/OpenSans-SemiBold.ttf" | |
android:textColor="@color/primary_text_color" | |
app:layout_constraintTop_toTopOf="@id/back_button" | |
app:layout_constraintBottom_toBottomOf="@id/back_button" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" /> | |
<androidx.appcompat.widget.AppCompatImageView | |
android:id="@+id/cardTypesView" | |
android:src="@drawable/card_types" | |
android:layout_width="match_parent" | |
android:layout_height="@dimen/_100sdp" | |
android:layout_marginTop="@dimen/_15sdp" | |
app:layout_constraintTop_toBottomOf="@id/back_button" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintEnd_toEndOf="parent"/> | |
<LinearLayout | |
android:id="@+id/amountView" | |
android:orientation="vertical" | |
android:layout_width="0dp" | |
android:layout_height="wrap_content" | |
android:gravity="center_horizontal|center_vertical" | |
android:padding="@dimen/_10sdp" | |
android:background="@drawable/border_grey_frame" | |
android:layout_marginTop="@dimen/_15sdp" | |
android:layout_marginStart="@dimen/_20sdp" | |
android:layout_marginEnd="@dimen/_20sdp" | |
app:layout_constraintTop_toBottomOf="@id/cardTypesView" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintEnd_toEndOf="parent"> | |
<androidx.appcompat.widget.AppCompatTextView | |
android:id="@+id/amountOutstandingLabelView" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="@string/total_payable" | |
android:gravity="center" | |
android:textSize="@dimen/_12ssp" | |
android:textColor="@color/secondary_text_color"/> | |
<androidx.appcompat.widget.AppCompatTextView | |
android:id="@+id/amountPayableTextView" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="@string/dash_text" | |
android:gravity="center" | |
android:textSize="@dimen/_18ssp" | |
android:layout_margin="@dimen/_3sdp" | |
fontPath="fonts/OpenSans-SemiBold.ttf" | |
android:textColor="@color/primary_text_color"/> | |
<androidx.appcompat.widget.AppCompatTextView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="@string/additional_transaction_fee" | |
android:gravity="center" | |
android:textSize="@dimen/_10ssp" | |
android:textColor="@color/app_red_seat"/> | |
</LinearLayout> | |
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes | |
android:id="@+id/cardNumberView" | |
android:layout_width="0dp" | |
android:layout_height="wrap_content" | |
app:labelText="@string/card_number" | |
app:hasClearButton="true" | |
android:layout_marginTop="@dimen/_15sdp" | |
app:layout_constraintTop_toBottomOf="@id/amountView" | |
app:layout_constraintStart_toStartOf="@id/amountView" | |
app:layout_constraintEnd_toEndOf="@id/amountView"> | |
<studio.carbonylgroup.textfieldboxes.ExtendedEditText | |
android:id="@+id/cardNumberTextBox" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:textColor="@color/primary_text_color" | |
android:textColorHint="@color/hint_text_color" | |
android:imeOptions="actionNext" | |
android:textSize="@dimen/_14ssp" | |
android:inputType="number" | |
android:maxLines="1"/> | |
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes> | |
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes | |
android:id="@+id/cardMonthView" | |
android:layout_width="0dp" | |
android:layout_height="wrap_content" | |
app:labelText="@string/mm" | |
app:hasClearButton="true" | |
android:layout_marginTop="@dimen/_15sdp" | |
app:layout_constraintTop_toBottomOf="@id/cardNumberView" | |
app:layout_constraintStart_toStartOf="@id/cardNumberView" | |
app:layout_constraintEnd_toStartOf="@id/cardYearView"> | |
<studio.carbonylgroup.textfieldboxes.ExtendedEditText | |
android:id="@+id/cardMonthViewTextBox" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:textColor="@color/primary_text_color" | |
android:textColorHint="@color/hint_text_color" | |
android:imeOptions="actionNext" | |
android:maxLength="2" | |
android:textSize="@dimen/_14ssp" | |
android:inputType="number" | |
android:maxLines="1"/> | |
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes> | |
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes | |
android:id="@+id/cardYearView" | |
android:layout_width="0dp" | |
android:layout_height="wrap_content" | |
app:labelText="@string/yy" | |
app:hasClearButton="true" | |
android:layout_marginStart="@dimen/_5sdp" | |
android:layout_marginEnd="@dimen/_5sdp" | |
app:layout_constraintTop_toTopOf="@id/cardMonthView" | |
app:layout_constraintBottom_toBottomOf="@id/cardMonthView" | |
app:layout_constraintStart_toEndOf="@id/cardMonthView" | |
app:layout_constraintEnd_toStartOf="@id/cardCVVView"> | |
<studio.carbonylgroup.textfieldboxes.ExtendedEditText | |
android:id="@+id/cardYearViewTextBox" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:textColor="@color/primary_text_color" | |
android:textColorHint="@color/hint_text_color" | |
android:imeOptions="actionNext" | |
android:maxLength="2" | |
android:textSize="@dimen/_14ssp" | |
android:inputType="number" | |
android:maxLines="1"/> | |
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes> | |
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes | |
android:id="@+id/cardCVVView" | |
android:layout_width="0dp" | |
android:layout_height="wrap_content" | |
app:labelText="@string/cvv" | |
app:hasClearButton="true" | |
app:layout_constraintTop_toTopOf="@id/cardMonthView" | |
app:layout_constraintBottom_toBottomOf="@id/cardMonthView" | |
app:layout_constraintStart_toEndOf="@id/cardYearView" | |
app:layout_constraintEnd_toEndOf="@id/cardNumberView"> | |
<studio.carbonylgroup.textfieldboxes.ExtendedEditText | |
android:id="@+id/cardCVVViewTextBox" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:textColor="@color/primary_text_color" | |
android:textColorHint="@color/hint_text_color" | |
android:imeOptions="actionDone" | |
android:maxLength="3" | |
android:textSize="@dimen/_14ssp" | |
android:inputType="number" | |
android:maxLines="1"/> | |
</studio.carbonylgroup.textfieldboxes.TextFieldBoxes> | |
<androidx.appcompat.widget.AppCompatButton | |
android:id="@+id/payNowButton" | |
android:layout_width="0dp" | |
android:layout_height="@dimen/button_height" | |
android:text="@string/pay_now" | |
android:layout_marginTop="@dimen/_14sdp" | |
android:layout_marginBottom="@dimen/_20sdp" | |
android:textSize="@dimen/_14ssp" | |
android:textAllCaps="false" | |
android:textColor="@color/app_white" | |
app:layout_constraintTop_toBottomOf="@id/cardMonthView" | |
app:layout_constraintStart_toStartOf="@id/cardNumberView" | |
app:layout_constraintEnd_toEndOf="@id/cardNumberView"/> | |
<LinearLayout | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:orientation="horizontal" | |
android:gravity="center" | |
android:layout_gravity="center_horizontal" | |
android:layout_marginTop="@dimen/_10sdp" | |
android:layout_marginBottom="@dimen/_20sdp" | |
app:layout_constraintTop_toBottomOf="@id/payNowButton" | |
app:layout_constraintStart_toStartOf="@id/payNowButton" | |
app:layout_constraintEnd_toEndOf="@id/payNowButton" | |
app:layout_constraintBottom_toBottomOf="parent"> | |
<androidx.appcompat.widget.AppCompatImageView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
app:srcCompat="@drawable/ic_lock" | |
android:tint="@color/icon_color"/> | |
<androidx.appcompat.widget.AppCompatTextView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="@string/secured_by_paystack" | |
android:textColor="@color/secondary_text_color"/> | |
</LinearLayout> | |
</androidx.constraintlayout.widget.ConstraintLayout> | |
</androidx.core.widget.NestedScrollView> |
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
public class CardPaymentActivity extends BaseActivity { | |
@BindView(R.id.cardNumberView) | |
TextFieldBoxes cardNumberView; | |
@BindView(R.id.cardMonthView) | |
TextFieldBoxes cardMonthView; | |
@BindView(R.id.cardYearView) | |
TextFieldBoxes cardYearView; | |
@BindView(R.id.cardCVVView) | |
TextFieldBoxes cardCVVView; | |
@BindView(R.id.cardNumberTextBox) | |
ExtendedEditText cardNumberTextBox; | |
@BindView(R.id.cardMonthViewTextBox) | |
ExtendedEditText cardMonthViewTextBox; | |
@BindView(R.id.cardYearViewTextBox) | |
ExtendedEditText cardYearViewTextBox; | |
@BindView(R.id.cardCVVViewTextBox) | |
ExtendedEditText cardCVVViewTextBox; | |
@BindView(R.id.amountPayableTextView) | |
AppCompatTextView amountPayableTextView; | |
// Class Properties | |
private String accessCode; | |
private double amount; | |
private String email; | |
private CountDownTimer activityCountDownTimer; | |
private CustomProgressDialog customProgressDialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_card_payment); | |
fetchDataFromBundle(); | |
initHelpers(); | |
initWatchers(); | |
initViews(); | |
} | |
private void fetchDataFromBundle() { | |
accessCode = getIntent().getStringExtra(PAYMENT_ACCESS_CODE_OBJECT); | |
amount = getIntent().getDoubleExtra(PAYMENT_AMOUNT_OBJECT, 0); | |
email = getIntent().getStringExtra(PAYMENT_EMAIL_OBJECT); | |
} | |
private void initHelpers() { | |
customProgressDialog = new CustomProgressDialog(this); | |
} | |
private void initWatchers() { | |
cardNumberTextBox.addTextChangedListener(cardWatcher); | |
cardMonthViewTextBox.addTextChangedListener(new ExpiryWatcher(cardMonthViewTextBox)); | |
cardYearViewTextBox.addTextChangedListener(new ExpiryWatcher(cardYearViewTextBox)); | |
} | |
private void initViews() { | |
String parsedAmount = parseAmount(String.valueOf(amount)); | |
if (!TextUtils.isEmpty(parsedAmount)) { | |
amountPayableTextView.setText(String.format("₦%1$s", parsedAmount)); | |
} | |
} | |
public void showProgress(boolean show) { | |
if (show) { | |
customProgressDialog.showDialog(); | |
} else { | |
customProgressDialog.hideDialog(); | |
} | |
} | |
public void showErrorDialog(String message) { | |
AppSuccessErrorDialog appSuccessErrorDialog = new AppSuccessErrorDialog(this, | |
DialogType.TYPE_ERROR, message); | |
appSuccessErrorDialog.showDialog(); | |
} | |
private void doShowSessionExpiredDialog() { | |
SessionExpiredDialog sessionExpiredDialog = new SessionExpiredDialog(this); | |
sessionExpiredDialog.setCallBack(this::doGotoHomeScreen); | |
sessionExpiredDialog.showDialog(); | |
} | |
private void doGotoHomeScreen() { | |
Intent intent = new Intent(this, Main2Activity.class); | |
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); | |
startActivity(intent); | |
finish(); | |
} | |
// Click Methods-------------------------------------------------------------------------------- | |
@OnClick(R.id.back_button) | |
void onBackButtonClicked() { | |
onBackPressed(); | |
} | |
@OnClick(R.id.payNowButton) | |
void onPayNowButtonClicked() { | |
String cardNum = cardNumberTextBox.getText().toString().trim(); | |
String cvv = cardCVVViewTextBox.getText().toString().trim(); | |
String sMonth = cardMonthViewTextBox.getText().toString().trim(); | |
String sYear = cardYearViewTextBox.getText().toString().trim(); | |
if (TextUtils.isEmpty(cardNum)) { | |
cardNumberView.setError("Empty card number", true); | |
return; | |
} | |
if (CommonUtils.inputShort(cardNum, 16)) { | |
cardNumberView.setError("Invalid card number", true); | |
return; | |
} | |
if (TextUtils.isEmpty(sMonth)) { | |
cardMonthView.setError("Required", true); | |
return; | |
} | |
if (TextUtils.isEmpty(sYear)) { | |
cardYearView.setError("Required", true); | |
return; | |
} | |
if (TextUtils.isEmpty(cvv)) { | |
cardCVVView.setError("Required", true); | |
return; | |
} | |
if (CommonUtils.inputShort(cvv, 3)) { | |
cardCVVView.setError("Invalid", true); | |
return; | |
} | |
//do Check Card | |
} | |
// Overridden Methods--------------------------------------------------------------------------- | |
@Override | |
protected void onDestroy() { | |
cardNumberTextBox.removeTextChangedListener(cardWatcher); | |
super.onDestroy(); | |
} | |
// Text Watchers-------------------------------------------------------------------------------- | |
private TextWatcher cardWatcher = new TextWatcher() { | |
@Override | |
public void beforeTextChanged(CharSequence s, int start, int count, int after) {/*EMPTY METHOD*/} | |
@Override | |
public void onTextChanged(CharSequence s, int start, int before, int count) {/*EMPTY METHOD*/} | |
@Override | |
public void afterTextChanged(Editable s) { | |
String number = s.toString(); | |
if (number.length() >= 4) { | |
String formatted = CommonUtils.formatForViewing(number, 4); | |
if (!number.equalsIgnoreCase(formatted)) { | |
cardNumberTextBox.removeTextChangedListener(cardWatcher); | |
cardNumberTextBox.setText(formatted); | |
cardNumberTextBox.setSelection(formatted.length()); | |
cardNumberTextBox.addTextChangedListener(cardWatcher); | |
} | |
} | |
} | |
}; | |
private class ExpiryWatcher implements TextWatcher { | |
private ExtendedEditText editText; | |
ExpiryWatcher(ExtendedEditText editText) { | |
this.editText = editText; | |
} | |
@Override | |
public void beforeTextChanged(CharSequence s, int start, int count, int after) {/*EMPTY METHOD*/} | |
@Override | |
public void onTextChanged(CharSequence s, int start, int before, int count) {/*EMPTY METHOD*/} | |
@Override | |
public void afterTextChanged(Editable s) { | |
try { | |
int number = Integer.parseInt(s.toString()); | |
int length = s.length(); | |
switch (editText.getId()) { | |
case R.id.cardMonthViewTextBox: | |
checkCardMonth(length, number); | |
break; | |
case R.id.cardYearViewTextBox: | |
checkCardYear(length, number); | |
break; | |
} | |
} catch (NumberFormatException nfe) { | |
nfe.printStackTrace(); | |
} | |
} | |
private void checkCardMonth(int length, int number) { | |
if (length == 1) { | |
if (number > 1) { | |
//add a 0 in front | |
setText("0"+number); | |
} | |
} else { | |
if (number > 12) { | |
setText("12"); | |
} | |
//request focus on the next field | |
cardYearView.requestFocus(); | |
} | |
} | |
private void checkCardYear(int length, int number) { | |
String stringYear = (Calendar.getInstance().get(Calendar.YEAR) + "").substring(2); | |
int currentYear = Integer.parseInt(stringYear); | |
if (length == 1) { | |
int firstDigit = Integer.parseInt(String.valueOf(currentYear).substring(0, length)); | |
if(number < firstDigit) { | |
setText(firstDigit+""); | |
} | |
} else { | |
if (number < currentYear){ | |
setText(currentYear+""); | |
} | |
cardCVVView.requestFocus(); | |
} | |
} | |
private void setText(String text) { | |
editText.setText(text); | |
editText.setSelection(editText.getText().toString().trim().length()); | |
} | |
} | |
} |
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
public class CommonUtils { | |
private static String cleanNumber(String number) { | |
return number.replaceAll("\\s", ""); | |
} | |
public static String formatForViewing(String enteredNumber, int maxLength) { | |
String cleaned = cleanNumber(enteredNumber); | |
int len = cleaned.length(); | |
if (len <= maxLength) | |
return cleaned; | |
ArrayList<String> gaps = new ArrayList<>(); | |
int[] segmentLengths = {0, 0, 0, 0}; | |
// { 4-4-4-4-4} | |
gaps.add(" "); | |
segmentLengths[0] = 4; | |
gaps.add(" "); | |
segmentLengths[1] = 4; | |
gaps.add(" "); | |
segmentLengths[2] = 4; | |
gaps.add(" "); | |
segmentLengths[3] = 4; | |
int end = maxLength; | |
int start; | |
String segment1 = cleaned.substring(0, end); | |
start = end; | |
end = Math.min(segmentLengths[0] + end, len); | |
String segment2 = cleaned.substring(start, end); | |
start = end; | |
end = Math.min(segmentLengths[1] + end, len); | |
String segment3 = cleaned.substring(start, end); | |
start = end; | |
end = Math.min(segmentLengths[2] + end, len); | |
String segment4 = cleaned.substring(start, end); | |
start = end; | |
end = Math.min(segmentLengths[3] + end, len); | |
String segment5 = cleaned.substring(start, end); | |
String ret = String.format("%s%s%s%s%s%s%s%s%s", | |
segment1, gaps.get(0), | |
segment2, gaps.get(1), | |
segment3, gaps.get(2), | |
segment4, gaps.get(2), | |
segment5); | |
return ret.trim(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment