Skip to content

Commit c70354f

Browse files
Clean up CardInputWidget and related classes (#1815)
Convert `CardNumberEditText` and `ExpiryDateEditText` listener interfaces to function types.
1 parent 7c74e76 commit c70354f

File tree

8 files changed

+190
-235
lines changed

8 files changed

+190
-235
lines changed

example/src/main/java/com/stripe/example/activity/LauncherActivity.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ package com.stripe.example.activity
33
import android.app.Activity
44
import android.content.Intent
55
import android.os.Bundle
6-
import android.view.LayoutInflater
76
import android.view.View
87
import android.view.ViewGroup
98
import android.widget.TextView
109
import androidx.appcompat.app.AppCompatActivity
1110
import androidx.recyclerview.widget.LinearLayoutManager
11+
import androidx.recyclerview.widget.RecyclerView
1212
import com.stripe.android.PaymentConfiguration
1313
import com.stripe.example.R
1414
import com.stripe.example.Settings
@@ -23,7 +23,9 @@ class LauncherActivity : AppCompatActivity() {
2323
PaymentConfiguration.init(this, Settings.PUBLISHABLE_KEY)
2424

2525
val linearLayoutManager = LinearLayoutManager(this)
26-
linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
26+
.apply {
27+
orientation = LinearLayoutManager.VERTICAL
28+
}
2729

2830
examples.run {
2931
setHasFixedSize(true)
@@ -34,7 +36,7 @@ class LauncherActivity : AppCompatActivity() {
3436

3537
private class ExamplesAdapter constructor(
3638
private val activity: Activity
37-
) : androidx.recyclerview.widget.RecyclerView.Adapter<ExamplesAdapter.ExamplesViewHolder>() {
39+
) : RecyclerView.Adapter<ExamplesAdapter.ExamplesViewHolder>() {
3840
private val items = listOf(
3941
Item(activity.getString(R.string.payment_auth_example),
4042
PaymentAuthActivity::class.java),
@@ -59,14 +61,15 @@ class LauncherActivity : AppCompatActivity() {
5961
)
6062

6163
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ExamplesViewHolder {
62-
val root = LayoutInflater.from(viewGroup.context)
64+
val root = activity.layoutInflater
6365
.inflate(R.layout.launcher_item, viewGroup, false)
6466
return ExamplesViewHolder(root)
6567
}
6668

6769
override fun onBindViewHolder(examplesViewHolder: ExamplesViewHolder, i: Int) {
68-
(examplesViewHolder.itemView as TextView).text = items[i].text
69-
examplesViewHolder.itemView.setOnClickListener {
70+
val itemView = examplesViewHolder.itemView
71+
(itemView as TextView).text = items[i].text
72+
itemView.setOnClickListener {
7073
activity.startActivity(Intent(activity, items[i].activityClass))
7174
}
7275
}
@@ -79,6 +82,6 @@ class LauncherActivity : AppCompatActivity() {
7982

8083
private class ExamplesViewHolder constructor(
8184
itemView: View
82-
) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView)
85+
) : RecyclerView.ViewHolder(itemView)
8386
}
8487
}

stripe/src/main/java/com/stripe/android/view/CardInputWidget.kt

Lines changed: 78 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class CardInputWidget @JvmOverloads constructor(
4545
) : LinearLayout(context, attrs, defStyleAttr), CardWidget {
4646
private val cardIconImageView: ImageView
4747
private val frameLayout: FrameLayout
48+
4849
private val cardNumberEditText: CardNumberEditText
4950
private val cvcNumberEditText: StripeEditText
5051
private val expiryDateEditText: ExpiryDateEditText
@@ -267,12 +268,10 @@ class CardInputWidget @JvmOverloads constructor(
267268
return super.onInterceptTouchEvent(ev)
268269
}
269270

270-
val focusEditText = getFocusRequestOnTouch(ev.x.toInt())
271-
if (focusEditText != null) {
272-
focusEditText.requestFocus()
273-
return true
274-
}
275-
return super.onInterceptTouchEvent(ev)
271+
return getFocusRequestOnTouch(ev.x.toInt())?.let {
272+
it.requestFocus()
273+
true
274+
} ?: super.onInterceptTouchEvent(ev)
276275
}
277276

278277
override fun onSaveInstanceState(): Parcelable {
@@ -460,11 +459,10 @@ class CardInputWidget @JvmOverloads constructor(
460459
info: AccessibilityNodeInfoCompat
461460
) {
462461
super.onInitializeAccessibilityNodeInfo(host, info)
463-
val accLabel = resources.getString(
462+
info.text = resources.getString(
464463
R.string.acc_label_cvc_node,
465464
cvcNumberEditText.text
466465
)
467-
info.text = accLabel
468466
}
469467
})
470468

@@ -509,11 +507,8 @@ class CardInputWidget @JvmOverloads constructor(
509507
}
510508
}
511509

512-
expiryDateEditText.setDeleteEmptyListener(
513-
BackUpFieldDeleteListener(cardNumberEditText))
514-
515-
cvcNumberEditText.setDeleteEmptyListener(
516-
BackUpFieldDeleteListener(expiryDateEditText))
510+
expiryDateEditText.setDeleteEmptyListener(BackUpFieldDeleteListener(cardNumberEditText))
511+
cvcNumberEditText.setDeleteEmptyListener(BackUpFieldDeleteListener(expiryDateEditText))
517512

518513
cvcNumberEditText.onFocusChangeListener = OnFocusChangeListener { _, hasFocus ->
519514
if (hasFocus) {
@@ -540,33 +535,21 @@ class CardInputWidget @JvmOverloads constructor(
540535
}
541536
)
542537

543-
cardNumberEditText.setCardNumberCompleteListener(
544-
object : CardNumberEditText.CardNumberCompleteListener {
545-
override fun onCardNumberComplete() {
546-
scrollRight()
547-
cardInputListener?.onCardComplete()
548-
}
549-
}
550-
)
538+
cardNumberEditText.completionCallback = {
539+
scrollRight()
540+
cardInputListener?.onCardComplete()
541+
}
551542

552-
cardNumberEditText.setCardBrandChangeListener(
553-
object : CardNumberEditText.CardBrandChangeListener {
554-
override fun onCardBrandChanged(brand: String) {
555-
isAmEx = CardBrand.AMERICAN_EXPRESS == brand
556-
updateIcon(brand)
557-
updateCvc(brand)
558-
}
559-
}
560-
)
543+
cardNumberEditText.brandChangeCallback = { brand ->
544+
isAmEx = CardBrand.AMERICAN_EXPRESS == brand
545+
updateIcon(brand)
546+
updateCvc(brand)
547+
}
561548

562-
expiryDateEditText.setExpiryDateEditListener(
563-
object : ExpiryDateEditText.ExpiryDateEditListener {
564-
override fun onExpiryDateComplete() {
565-
cvcNumberEditText.requestFocus()
566-
cardInputListener?.onExpirationComplete()
567-
}
568-
}
569-
)
549+
expiryDateEditText.completionCallback = {
550+
cvcNumberEditText.requestFocus()
551+
cardInputListener?.onExpirationComplete()
552+
}
570553

571554
cardNumberEditText.requestFocus()
572555
}
@@ -627,10 +610,11 @@ class CardInputWidget @JvmOverloads constructor(
627610
slideDateLeftAnimation.duration = ANIMATION_LENGTH
628611
slideCvcLeftAnimation.duration = ANIMATION_LENGTH
629612

630-
val animationSet = AnimationSet(true)
631-
animationSet.addAnimation(slideCardLeftAnimation)
632-
animationSet.addAnimation(slideDateLeftAnimation)
633-
animationSet.addAnimation(slideCvcLeftAnimation)
613+
val animationSet = AnimationSet(true).apply {
614+
addAnimation(slideCardLeftAnimation)
615+
addAnimation(slideDateLeftAnimation)
616+
addAnimation(slideCvcLeftAnimation)
617+
}
634618
frameLayout.startAnimation(animationSet)
635619
cardNumberIsViewed = true
636620
}
@@ -642,7 +626,7 @@ class CardInputWidget @JvmOverloads constructor(
642626

643627
val dateStartMargin = placementParameters.cardWidth + placementParameters.cardDateSeparation
644628

645-
updateSpaceSizes(false)
629+
updateSpaceSizes(isCardViewed = false)
646630

647631
val slideCardRightAnimation = object : Animation() {
648632
override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
@@ -693,10 +677,11 @@ class CardInputWidget @JvmOverloads constructor(
693677
}
694678
})
695679

696-
val animationSet = AnimationSet(true)
697-
animationSet.addAnimation(slideCardRightAnimation)
698-
animationSet.addAnimation(slideDateRightAnimation)
699-
animationSet.addAnimation(slideCvcRightAnimation)
680+
val animationSet = AnimationSet(true).apply {
681+
addAnimation(slideCardRightAnimation)
682+
addAnimation(slideDateRightAnimation)
683+
addAnimation(slideCvcRightAnimation)
684+
}
700685

701686
frameLayout.startAnimation(animationSet)
702687
cardNumberIsViewed = false
@@ -724,10 +709,11 @@ class CardInputWidget @JvmOverloads constructor(
724709
}
725710
setLayoutValues(placementParameters.cardWidth, cardLeftMargin, cardNumberEditText)
726711

727-
val dateMargin = if (cardNumberIsViewed)
712+
val dateMargin = if (cardNumberIsViewed) {
728713
placementParameters.cardWidth + placementParameters.cardDateSeparation
729-
else
714+
} else {
730715
placementParameters.peekCardWidth + placementParameters.cardDateSeparation
716+
}
731717
setLayoutValues(placementParameters.dateWidth, dateMargin, expiryDateEditText)
732718

733719
val cvcMargin = if (cardNumberIsViewed) {
@@ -781,10 +767,10 @@ class CardInputWidget @JvmOverloads constructor(
781767

782768
private fun updateCvc(@Card.CardBrand brand: String) {
783769
if (CardBrand.AMERICAN_EXPRESS == brand) {
784-
cvcNumberEditText.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(Card.CVC_LENGTH_AMERICAN_EXPRESS))
770+
cvcNumberEditText.filters = INPUT_FILTER_AMEX
785771
cvcNumberEditText.setHint(R.string.cvc_amex_hint)
786772
} else {
787-
cvcNumberEditText.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(Card.CVC_LENGTH_COMMON))
773+
cvcNumberEditText.filters = INPUT_FILTER_COMMON
788774
cvcNumberEditText.setHint(R.string.cvc_number_hint)
789775
}
790776
}
@@ -812,54 +798,59 @@ class CardInputWidget @JvmOverloads constructor(
812798
}
813799

814800
private fun updateIconForCvcEntry(isAmEx: Boolean) {
815-
if (isAmEx) {
816-
cardIconImageView.setImageResource(R.drawable.ic_cvc_amex)
801+
cardIconImageView.setImageResource(if (isAmEx) {
802+
R.drawable.ic_cvc_amex
817803
} else {
818-
cardIconImageView.setImageResource(R.drawable.ic_cvc)
819-
}
804+
R.drawable.ic_cvc
805+
})
820806
applyTint(true)
821807
}
822808

823809
/**
824810
* Interface useful for testing calculations without generating real views.
825811
*/
826-
@VisibleForTesting
827812
internal interface DimensionOverrideSettings {
828-
829813
val frameWidth: Int
814+
830815
fun getPixelWidth(text: String, editText: EditText): Int
831816
}
832817

833818
/**
834819
* A data-dump class.
835820
*/
836821
internal class PlacementParameters {
837-
var cardWidth: Int = 0
838-
var hiddenCardWidth: Int = 0
839-
var peekCardWidth: Int = 0
840-
var cardDateSeparation: Int = 0
841-
var dateWidth: Int = 0
842-
var dateCvcSeparation: Int = 0
843-
var cvcWidth: Int = 0
844-
845-
var cardTouchBufferLimit: Int = 0
846-
var dateStartPosition: Int = 0
847-
var dateRightTouchBufferLimit: Int = 0
848-
var cvcStartPosition: Int = 0
822+
internal var cardWidth: Int = 0
823+
internal var hiddenCardWidth: Int = 0
824+
internal var peekCardWidth: Int = 0
825+
internal var cardDateSeparation: Int = 0
826+
internal var dateWidth: Int = 0
827+
internal var dateCvcSeparation: Int = 0
828+
internal var cvcWidth: Int = 0
829+
830+
internal var cardTouchBufferLimit: Int = 0
831+
internal var dateStartPosition: Int = 0
832+
internal var dateRightTouchBufferLimit: Int = 0
833+
internal var cvcStartPosition: Int = 0
849834

850835
override fun toString(): String {
851-
val touchBufferData = "Touch Buffer Data:\n" +
852-
"CardTouchBufferLimit = $cardTouchBufferLimit\n" +
853-
"DateStartPosition = $dateStartPosition\n" +
854-
"DateRightTouchBufferLimit = $dateRightTouchBufferLimit\n" +
836+
val touchBufferData = """
837+
Touch Buffer Data:
838+
"CardTouchBufferLimit = $cardTouchBufferLimit
839+
"DateStartPosition = $dateStartPosition
840+
"DateRightTouchBufferLimit = $dateRightTouchBufferLimit
855841
"CvcStartPosition = $cvcStartPosition"
856-
val elementSizeData = "CardWidth = $cardWidth\n" +
857-
"HiddenCardWidth = $hiddenCardWidth\n" +
858-
"PeekCardWidth = $peekCardWidth\n" +
859-
"CardDateSeparation = $cardDateSeparation\n" +
860-
"DateWidth = $dateWidth\n" +
861-
"DateCvcSeparation = $dateCvcSeparation\n" +
862-
"CvcWidth = $cvcWidth\n"
842+
"""
843+
844+
val elementSizeData = """
845+
CardWidth = $cardWidth
846+
HiddenCardWidth = $hiddenCardWidth
847+
PeekCardWidth = $peekCardWidth
848+
CardDateSeparation = $cardDateSeparation
849+
DateWidth = $dateWidth
850+
DateCvcSeparation = $dateCvcSeparation
851+
CvcWidth = $cvcWidth
852+
"""
853+
863854
return elementSizeData + touchBufferData
864855
}
865856
}
@@ -904,6 +895,12 @@ class CardInputWidget @JvmOverloads constructor(
904895

905896
private const val ANIMATION_LENGTH = 150L
906897

898+
private val INPUT_FILTER_AMEX: Array<InputFilter> =
899+
arrayOf(InputFilter.LengthFilter(Card.CVC_LENGTH_AMERICAN_EXPRESS))
900+
901+
private val INPUT_FILTER_COMMON: Array<InputFilter> =
902+
arrayOf(InputFilter.LengthFilter(Card.CVC_LENGTH_COMMON))
903+
907904
/**
908905
* Determines whether or not the icon should show the card brand instead of the
909906
* CVC helper icon.
@@ -920,9 +917,7 @@ class CardInputWidget @JvmOverloads constructor(
920917
cvcHasFocus: Boolean,
921918
cvcText: String?
922919
): Boolean {
923-
return if (!cvcHasFocus) {
924-
true
925-
} else ViewUtils.isCvcMaximalLength(brand, cvcText)
920+
return !cvcHasFocus || ViewUtils.isCvcMaximalLength(brand, cvcText)
926921
}
927922
}
928923
}

stripe/src/main/java/com/stripe/android/view/CardMultilineWidget.kt

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -222,32 +222,20 @@ class CardMultilineWidget @JvmOverloads constructor(
222222
initFocusChangeListeners()
223223
initDeleteEmptyListeners()
224224

225-
cardNumberEditText.setCardNumberCompleteListener(
226-
object : CardNumberEditText.CardNumberCompleteListener {
227-
override fun onCardNumberComplete() {
228-
expiryDateEditText.requestFocus()
229-
cardInputListener?.onCardComplete()
230-
}
231-
}
232-
)
225+
cardNumberEditText.completionCallback = {
226+
expiryDateEditText.requestFocus()
227+
cardInputListener?.onCardComplete()
228+
}
233229

234-
cardNumberEditText.setCardBrandChangeListener(
235-
object : CardNumberEditText.CardBrandChangeListener {
236-
override fun onCardBrandChanged(brand: String) {
237-
cardBrand = brand
238-
updateBrandUi()
239-
}
240-
}
241-
)
230+
cardNumberEditText.brandChangeCallback = { brand ->
231+
cardBrand = brand
232+
updateBrandUi()
233+
}
242234

243-
expiryDateEditText.setExpiryDateEditListener(
244-
object : ExpiryDateEditText.ExpiryDateEditListener {
245-
override fun onExpiryDateComplete() {
246-
cvcEditText.requestFocus()
247-
cardInputListener?.onExpirationComplete()
248-
}
249-
}
250-
)
235+
expiryDateEditText.completionCallback = {
236+
cvcEditText.requestFocus()
237+
cardInputListener?.onExpirationComplete()
238+
}
251239

252240
cvcEditText.setAfterTextChangedListener(
253241
object : StripeEditText.AfterTextChangedListener {

0 commit comments

Comments
 (0)