Skip to content

Commit 8f39ef6

Browse files
Merge pull request #156 from skyflowapi/release/23.10.1
SK-1112/Release/23.10.1
2 parents 7a2e9d0 + e0e22c6 commit 8f39ef6

10 files changed

Lines changed: 213 additions & 5 deletions

File tree

Skyflow/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ ext {
1010
mGroupId = "com.skyflowapi.android"
1111
mArtifactId = "skyflow-android-sdk"
1212
mVersionCode = 1
13-
mVersionName = "1.20.1"
13+
mVersionName = "1.20.1-dev.480e533"
1414

1515
mLibraryName = "skyflow-android"
1616
mLibraryDescription = "Skyflow’s android SDK can be used to securely collect, tokenize, and display sensitive data in the mobile without exposing your front-end infrastructure to sensitive data."

Skyflow/src/main/kotlin/Skyflow/CollectElementOptions.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class CollectElementOptions(
55
var enableCardIcon: Boolean = true,
66
var format: String = "",
77
var translation: HashMap<Char, String>? = null,
8+
val enableCopy: Boolean = false
89
) {
910
internal var inputFormat: HashMap<Char, Regex> = hashMapOf()
1011
private val HYPHEN_CARD_NUMBER_FORMAT = "XXXX-XXXX-XXXX-XXXX"

Skyflow/src/main/kotlin/Skyflow/Label.kt

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
package Skyflow
22

3+
import Skyflow.collect.elements.utils.VibrationHelper
34
import android.annotation.SuppressLint
5+
import android.content.ClipData
6+
import android.content.ClipboardManager
47
import android.content.Context
58
import android.graphics.Typeface
9+
import android.graphics.drawable.Drawable
610
import android.graphics.drawable.GradientDrawable
711
import android.os.Build
12+
import android.os.Handler
13+
import android.os.Looper
814
import android.util.AttributeSet
15+
import android.view.MotionEvent
916
import android.widget.LinearLayout
1017
import android.widget.TextView
1118
import androidx.annotation.RequiresApi
19+
import androidx.core.content.ContextCompat
1220
import androidx.core.content.res.ResourcesCompat
21+
import com.skyflow_android.R
1322

1423
@Suppress("DEPRECATION")
1524
class Label @JvmOverloads constructor(
@@ -28,6 +37,72 @@ class Label @JvmOverloads constructor(
2837
internal var isError = false
2938
internal var uuid = ""
3039

40+
private var drawableRight: Drawable? = null
41+
private var valueToCopy: String = ""
42+
43+
internal fun enableCopy(valueToCopy: String) {
44+
if (options.enableCopy) {
45+
this.valueToCopy = valueToCopy
46+
appendIcon("COPY")
47+
}
48+
}
49+
50+
private fun appendIcon(iconName: String) {
51+
lateinit var drawable: Drawable
52+
val copyDrawable = ContextCompat.getDrawable(context, R.drawable.ic_copy)
53+
val copiedDrawable = ContextCompat.getDrawable(context, R.drawable.ic_copied)
54+
55+
when (iconName) {
56+
"COPY" -> drawable = copyDrawable!!
57+
"COPIED" -> {
58+
drawable = copiedDrawable!!
59+
Handler(Looper.getMainLooper()).postDelayed({
60+
placeholder.setCompoundDrawablesWithIntrinsicBounds(
61+
null,
62+
null,
63+
copyDrawable,
64+
null
65+
)
66+
drawableRight = copyDrawable
67+
}, 2000) // 2000 milliseconds = 2 seconds
68+
}
69+
}
70+
placeholder.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, drawable, null)
71+
placeholder.compoundDrawablePadding = 8
72+
drawableRight = drawable
73+
}
74+
75+
override fun onTouchEvent(event: MotionEvent?): Boolean {
76+
when (event?.action) {
77+
MotionEvent.ACTION_DOWN -> {
78+
return performCopyAction(event)
79+
}
80+
}
81+
return super.onTouchEvent(event)
82+
}
83+
84+
private fun performCopyAction(event: MotionEvent): Boolean {
85+
val extraTapArea = 10
86+
val actionX = event.rawX
87+
if (drawableRight != null) {
88+
val wBound = placeholder.right - placeholder.compoundDrawables[2].bounds.width()
89+
if (actionX >= wBound - extraTapArea && actionX <= placeholder.right) {
90+
handleTap()
91+
return true
92+
}
93+
}
94+
return true
95+
}
96+
97+
private fun handleTap() {
98+
val textToCopy = this.valueToCopy
99+
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
100+
val clip = ClipData.newPlainText("CustomCopyTextView", textToCopy)
101+
clipboard.setPrimaryClip(clip)
102+
VibrationHelper.vibrate(context, 10)
103+
appendIcon("COPIED")
104+
}
105+
31106
fun getID(): String {
32107
return uuid
33108
}

Skyflow/src/main/kotlin/Skyflow/RevealElementOptions.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ class RevealElementOptions(
44
var formatRegex: String = "",
55
var replaceText: String? = null,
66
var format: String = "",
7-
var translation: HashMap<Char, String>? = null
7+
var translation: HashMap<Char, String>? = null,
8+
val enableCopy: Boolean = false
89
) {
910
internal var inputFormat: HashMap<Char, Regex> = hashMapOf()
1011

Skyflow/src/main/kotlin/Skyflow/TextField.kt

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ import androidx.annotation.RequiresApi
1919
import androidx.core.content.res.ResourcesCompat
2020
import Skyflow.core.elements.state.StateforText
2121
import Skyflow.utils.EventName
22+
import android.content.ClipData
23+
import android.content.ClipboardManager
2224
import android.graphics.Typeface
25+
import android.graphics.drawable.Drawable
26+
import android.os.Handler
27+
import android.os.Looper
2328
import android.text.Spanned
2429
import androidx.core.text.isDigitsOnly
2530
import com.skyflow_android.R
@@ -28,6 +33,8 @@ import kotlin.String
2833
import android.text.InputFilter
2934
import android.text.InputFilter.LengthFilter
3035
import android.util.Log
36+
import android.view.MotionEvent
37+
import androidx.core.content.ContextCompat
3138
import com.Skyflow.collect.elements.validations.*
3239
import com.Skyflow.collect.elements.validations.SkyflowValidator
3340
import com.Skyflow.collect.elements.validations.SkyflowValidateExpireDate
@@ -62,6 +69,8 @@ class TextField @JvmOverloads constructor(
6269

6370
private var isFormatting = false
6471

72+
private var drawableRight: Drawable? = null
73+
6574
override var uuid = ""
6675
override fun getValue(): String {
6776
return actualValue
@@ -100,6 +109,66 @@ class TextField @JvmOverloads constructor(
100109
}
101110
}
102111

112+
private fun appendIcon(iconName: String) {
113+
lateinit var drawable: Drawable
114+
val copyDrawable = ContextCompat.getDrawable(context, R.drawable.ic_copy)
115+
val copiedDrawable = ContextCompat.getDrawable(context, R.drawable.ic_copied)
116+
117+
when (iconName) {
118+
"COPY" -> drawable = copyDrawable!!
119+
"COPIED" -> {
120+
drawable = copiedDrawable!!
121+
Handler(Looper.getMainLooper()).postDelayed({
122+
inputField.setCompoundDrawablesWithIntrinsicBounds(
123+
null,
124+
null,
125+
copyDrawable,
126+
null
127+
)
128+
drawableRight = copyDrawable
129+
}, 2000) // 2000 milliseconds = 2 seconds
130+
}
131+
}
132+
inputField.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, drawable, null)
133+
inputField.compoundDrawablePadding = 8
134+
drawableRight = drawable
135+
}
136+
137+
private fun removeIcon() {
138+
inputField.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null)
139+
}
140+
141+
override fun onTouchEvent(event: MotionEvent?): Boolean {
142+
when (event?.action) {
143+
MotionEvent.ACTION_DOWN -> {
144+
return performCopyAction(event)
145+
}
146+
}
147+
return super.onTouchEvent(event)
148+
}
149+
150+
private fun performCopyAction(event: MotionEvent): Boolean {
151+
val extraTapArea = 10
152+
val actionX = event.rawX
153+
if (drawableRight != null) {
154+
val wBound = inputField.right - inputField.compoundDrawables[2].bounds.width()
155+
if (actionX >= wBound - extraTapArea && actionX <= inputField.right) {
156+
handleTap()
157+
return true
158+
}
159+
}
160+
return true
161+
}
162+
163+
private fun handleTap() {
164+
val textToCopy = this.actualValue
165+
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
166+
val clip = ClipData.newPlainText("CustomCopyTextView", textToCopy)
167+
clipboard.setPrimaryClip(clip)
168+
VibrationHelper.vibrate(context, 10)
169+
appendIcon("COPIED")
170+
}
171+
103172
override fun setupField(
104173
collectInput: CollectElementInput,
105174
options: CollectElementOptions
@@ -219,7 +288,6 @@ class TextField @JvmOverloads constructor(
219288
}
220289
}
221290

222-
223291
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
224292
public override fun onAttachedToWindow() {
225293
super.onAttachedToWindow()
@@ -240,11 +308,9 @@ class TextField @JvmOverloads constructor(
240308
//when text changes
241309
inputField.addTextChangedListener(object : TextWatcher {
242310
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
243-
244311
}
245312

246313
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
247-
248314
}
249315

250316
override fun afterTextChanged(s: Editable?) {
@@ -254,6 +320,13 @@ class TextField @JvmOverloads constructor(
254320
actualValue = inputField.text.toString()
255321
formatPatternForField(s)
256322
state = StateforText(this@TextField)
323+
if (state.getInternalState().getBoolean("isValid")){
324+
if (options.enableCopy) {
325+
appendIcon("COPY")
326+
}
327+
}else if (options.enableCopy){
328+
removeIcon()
329+
}
257330
if (userOnchangeListener !== null)
258331
userOnchangeListener?.let {
259332
it(

Skyflow/src/main/kotlin/Skyflow/utils/Utils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ public class Utils {
296296
val replaceText = label.options.replaceText
297297

298298
label.placeholder.setTextIsSelectable(true)
299+
label.enableCopy(value)
300+
299301
val format = label.options.format
300302
val translation = label.options.translation
301303
val DEFAULT_TRANSLATION = hashMapOf(Pair('X', "[0-9]"))
324 Bytes
Loading
238 Bytes
Loading

Skyflow/src/test/java/com/Skyflow/CollectTest.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,36 @@ class CollectTest {
14811481
pin.clearValue()
14821482
}
14831483

1484+
@Test
1485+
fun testCopyWhenEnableCopyIsTrue() {
1486+
val container = skyflow.container(ContainerType.COLLECT)
1487+
val options = CollectElementOptions(enableCopy = true)
1488+
val collectInput = CollectElementInput(
1489+
"cards", "card_number",
1490+
SkyflowElementType.CARD_NUMBER, placeholder = "XXXX"
1491+
)
1492+
val cardNumber = container.create(activity, collectInput, options)
1493+
cardNumber.onAttachedToWindow()
1494+
cardNumber.setText("4111111111111110")
1495+
Assert.assertNull(cardNumber.inputField.compoundDrawablesRelative[2])
1496+
cardNumber.setText("4111111111111111")
1497+
Assert.assertNotNull(cardNumber.inputField.compoundDrawablesRelative[2])
1498+
}
14841499

1500+
@Test
1501+
fun testCopyAndEnableCopyIsFalse() {
1502+
val container = skyflow.container(ContainerType.COLLECT)
1503+
val collectInput = CollectElementInput(
1504+
"cards", "card_number",
1505+
SkyflowElementType.CARD_NUMBER, placeholder = "XXXX"
1506+
)
1507+
val cardNumber = container.create(activity, collectInput)
1508+
cardNumber.onAttachedToWindow()
1509+
cardNumber.setText("4111111111111110")
1510+
Assert.assertNull(cardNumber.inputField.compoundDrawablesRelative[2])
1511+
cardNumber.setText("4111111111111111")
1512+
Assert.assertNull(cardNumber.inputField.compoundDrawablesRelative[2])
1513+
}
14851514
}
14861515

14871516

Skyflow/src/test/java/com/Skyflow/RevealTest.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,4 +986,31 @@ class RevealTest {
986986
}
987987
//end RevealValueCallback
988988

989+
@Test
990+
fun testCopyAndEnableCopyIsTrue() {
991+
val container = skyflow.container(ContainerType.REVEAL)
992+
val options = RevealElementOptions(format = "(XX)-XX", enableCopy = true)
993+
val revealInput = RevealElementInput("1234", null)
994+
val inputField = container.create(activity, revealInput, options)
995+
996+
Assert.assertNull(inputField.placeholder.compoundDrawablesRelative[2])
997+
Utils.setValueForLabel(inputField, "1234")
998+
Assert.assertNotNull(inputField.placeholder.compoundDrawablesRelative[2])
999+
Assert.assertEquals("1234", inputField.getValue())
1000+
Assert.assertEquals("(12)-34", inputField.placeholder.text.toString())
1001+
}
1002+
1003+
@Test
1004+
fun testCopyAndEnableCopyIsFalse() {
1005+
val container = skyflow.container(ContainerType.REVEAL)
1006+
val options = RevealElementOptions(format = "(XX)-XX")
1007+
val revealInput = RevealElementInput("1234", null)
1008+
val inputField = container.create(activity, revealInput, options)
1009+
1010+
Assert.assertNull(inputField.placeholder.compoundDrawablesRelative[2])
1011+
Utils.setValueForLabel(inputField, "1234")
1012+
Assert.assertNull(inputField.placeholder.compoundDrawablesRelative[2])
1013+
Assert.assertEquals("1234", inputField.getValue())
1014+
Assert.assertEquals("(12)-34", inputField.placeholder.text.toString())
1015+
}
9891016
}

0 commit comments

Comments
 (0)