Skip to content

Commit

Permalink
fix: image glitch and add url validations (RMCCX-7331, RMCCX-7345)
Browse files Browse the repository at this point in the history
  • Loading branch information
maureenorea-clores authored Sep 20, 2024
1 parent ab97a3e commit 4a4ffba
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,21 @@ internal fun UiMessage.applyCustomClickableImage(clickableImage: ClickableImage?
)
}

fun String?.isValidUrlOrDeeplink(): Boolean {
if (this.isNullOrBlank() || this != this.trim()) {
return false
}

return if (this.startsWith("http")) {
Regex("https://.*").matches(this)
} else {
Regex(".*://.*").matches(this)
}
}

@SuppressWarnings("ComplexCondition")
if (clickableImage == null ||
clickableImage.url.isNullOrEmpty() ||
!clickableImage.url.isValidUrlOrDeeplink() ||
imageUrl.isNullOrEmpty() ||
!type.campaignTypeCanBeClickable() ||
isPushPrimer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ internal open class InAppMessageBaseView(context: Context, attrs: AttributeSet?)
// load the image then display the view
this.visibility = GONE
findViewById<ImageView>(R.id.message_image_view)?.let { imgView ->
imgView.setOnTouchListener(this.listener)
if (!this.imageClickBehavior?.uri.isNullOrEmpty()) {
imgView.setOnClickListener(this.listener)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ internal class InAppMessageViewListener(
/**
* Callback When touch event occurred. Which will trigger to magnify message view content.
*/
@SuppressLint("NewApi", "ClickableViewAccessibility")
@SuppressLint("NewApi")
override fun onTouch(view: View, event: MotionEvent): Boolean {
if (buildChecker.isAndroidQAndAbove()) {
when (event.actionMasked) {
Expand All @@ -52,7 +52,7 @@ internal class InAppMessageViewListener(
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> this.magnifier?.dismiss()
else -> this.magnifier?.dismiss()
}
// No need to performClick as it will be handled by system through setOnClickListener if it is clickable
return view.performClick()
}
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,59 @@ class ApplyClickableImageSpec {
}

@Test
fun `should do nothing if url attribute does not exist or empty`() {
fun `should do nothing if url attribute is invalid`() {
var uiMessage = message.applyCustomClickableImage(ClickableImage(), false)
uiMessage shouldBeEqualTo message

uiMessage = message.applyCustomClickableImage(ClickableImage(""), false)
uiMessage shouldBeEqualTo message

uiMessage = message.applyCustomClickableImage(ClickableImage("ogle.124dsefsd"), false)
uiMessage shouldBeEqualTo message

uiMessage = message.applyCustomClickableImage(ClickableImage("http://test.com"), false)
uiMessage shouldBeEqualTo message

uiMessage = message.applyCustomClickableImage(ClickableImage(" myapp://open"), false)
uiMessage shouldBeEqualTo message

uiMessage = message.applyCustomClickableImage(ClickableImage("https://test.com "), false)
uiMessage shouldBeEqualTo message
}

@Test
fun `should do nothing if imageUrl does not exist or empty`() {
var uiMessage = message.copy(imageUrl = null)
.applyCustomClickableImage(ClickableImage("http://test.com"), false)
.applyCustomClickableImage(ClickableImage("https://test.com"), false)
uiMessage.content?.onClick?.uri shouldBeEqualTo null

uiMessage = message.copy(imageUrl = "")
.applyCustomClickableImage(ClickableImage("http://test.com"), false)
.applyCustomClickableImage(ClickableImage("https://test.com"), false)
uiMessage.content?.onClick?.uri shouldBeEqualTo null
}

@Test
fun `should do nothing if campaign layout isn't clickable`() {
val uiMessage = message.copy(type = InAppMessageType.SLIDE.typeId)
.applyCustomClickableImage(ClickableImage("http://test.com"), false)
.applyCustomClickableImage(ClickableImage("https://test.com"), false)

uiMessage.content?.onClick?.uri shouldBeEqualTo null
}

@Test
fun `should do nothing if campaign is a PushPrimer`() {
val uiMessage = message.copy(type = InAppMessageType.MODAL.typeId)
.applyCustomClickableImage(ClickableImage("http://test.com"), true)
.applyCustomClickableImage(ClickableImage("https://test.com"), true)

uiMessage.content?.onClick?.uri shouldBeEqualTo null
}

@Test
fun `should update content url to clickableImage url for null content data`() {
val uiMessage = message.copy(type = InAppMessageType.MODAL.typeId)
.applyCustomClickableImage(ClickableImage("http://test.com"), false)
.applyCustomClickableImage(ClickableImage("https://test.com"), false)

uiMessage.content?.onClick?.uri shouldBeEqualTo "http://test.com"
uiMessage.content?.onClick?.uri shouldBeEqualTo "https://test.com"
}

@Test
Expand All @@ -70,8 +82,8 @@ class ApplyClickableImageSpec {
type = InAppMessageType.MODAL.typeId,
content = Content(onClick = OnClickBehavior(3)),
)
.applyCustomClickableImage(ClickableImage("http://test.com"), false)
.applyCustomClickableImage(ClickableImage("myapp://open?param=value"), false)

uiMessage.content?.onClick?.uri shouldBeEqualTo "http://test.com"
uiMessage.content?.onClick?.uri shouldBeEqualTo "myapp://open?param=value"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ class MessageMapperSpec {
val uiMessage = MessageMapper.mapFrom(
TestDataHelper.createDummyMessage(
messagePayload = payload,
customJson = JsonParser.parseString("""{"clickableImage": { "url": "http://test.com" }}""")
customJson = JsonParser.parseString("""{"clickableImage": { "url": "https://test.com" }}""")
.asJsonObject,
),
)

uiMessage.content shouldNotBeEqualTo null
uiMessage.content?.onClick shouldNotBeEqualTo null
uiMessage.content?.onClick?.action shouldBeEqualTo ButtonActionType.REDIRECT.typeId
uiMessage.content?.onClick?.uri shouldBeEqualTo "http://test.com"
uiMessage.content?.onClick?.uri shouldBeEqualTo "https://test.com"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,78 +138,78 @@ class InAppMessageViewListenerOnTouchSpec : InAppMessageViewListenerSpec() {
}

@Test
fun `should return false on touch with action down and onClick listener`() {
fun `should return true on touch with action down and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_DOWN)

listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
}

@Test
fun `should return false on touch with action move and onClick listener`() {
fun `should return true on touch with action move and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_MOVE)

listener.magnifier = Mockito.mock(Magnifier::class.java)
listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
}

@Test
fun `should return false on touch with action cancel and onClick listener`() {
fun `should return true on touch with action cancel and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_CANCEL)

listener.magnifier = Mockito.mock(Magnifier::class.java)
listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
}

@Test
fun `should return false on touch with action up and onClick listener`() {
fun `should return true on touch with action up and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_UP)

listener.magnifier = Mockito.mock(Magnifier::class.java)
listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
}

@Test
fun `should return false on touch with other action and onClick listener`() {
fun `should return true on touch with other action and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_OUTSIDE)

listener.magnifier = Mockito.mock(Magnifier::class.java)
listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
}

@Test
fun `should return false on touch with action move, null magnifier, and onClick listener`() {
fun `should return true on touch with action move, null magnifier, and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_MOVE)

listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
listener.magnifier.shouldBeNull()
}

@Test
fun `should return false on touch with action cancel, null magnifier, and onClick listener`() {
fun `should return true on touch with action cancel, null magnifier, and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_CANCEL)

listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
listener.magnifier.shouldBeNull()
}

@Test
fun `should return false on touch with action up, null magnifier, and onClick listener`() {
fun `should return true on touch with action up, null magnifier, and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_UP)

listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
listener.magnifier.shouldBeNull()
}

@Test
fun `should return false on touch with other action, null magnifier, and onClick listener`() {
fun `should return true on touch with other action, null magnifier, and onClick listener`() {
val listener = setupListener(MotionEvent.ACTION_OUTSIDE)

listener.onTouch(mockView, mockMotionEvent).shouldBeFalse()
listener.onTouch(mockView, mockMotionEvent).shouldBeTrue()
listener.magnifier.shouldBeNull()
}

@Test
fun `should return false on touch with action down`() {
fun `should return true on touch with action down`() {
val listener = InAppMessageViewListener(
MessageMapper.mapFrom(
TestDataHelper.createDummyMessage(campaignId = "1", isTest = true),
Expand Down

0 comments on commit 4a4ffba

Please sign in to comment.