Skip to content

Commit 6b18e51

Browse files
authored
Merge pull request #1102 from wordpress-mobile/fix/handle-link-touch-events-aztectext-disabled
Add touch event handling in AztecText when field is disabled
2 parents 329c368 + 532a1f3 commit 6b18e51

File tree

2 files changed

+73
-37
lines changed

2 files changed

+73
-37
lines changed

aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
242242
private var bypassMediaDeletedListener: Boolean = false
243243
private var bypassCrashPreventerInputFilter: Boolean = false
244244
private var overrideSamsungPredictiveBehavior: Boolean = false
245+
private var allowLinkTapWhenDisable: Boolean = false
245246

246247
var initialEditorContentParsedSHA256: ByteArray = ByteArray(0)
247248

@@ -756,6 +757,12 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
756757
}
757758
}
758759

760+
// We need to handle touch events to links if they are disabled.
761+
if (allowLinkTapWhenDisable && !isEnabled &&
762+
EnhancedMovementMethod.handleLinkTouchEvent(widget = this, text = text, event = event).handled) {
763+
return false
764+
}
765+
759766
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
760767
&& event.action == MotionEvent.ACTION_DOWN) {
761768
// we'll use these values in OnLongClickListener
@@ -1919,6 +1926,10 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
19191926
overrideSamsungPredictiveBehavior = true
19201927
}
19211928

1929+
fun enableLinkTapWhenDisable() {
1930+
allowLinkTapWhenDisable = true
1931+
}
1932+
19221933
fun isMediaDeletedListenerDisabled(): Boolean {
19231934
return bypassMediaDeletedListener
19241935
}

aztec/src/main/kotlin/org/wordpress/aztec/EnhancedMovementMethod.kt

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,57 +47,82 @@ object EnhancedMovementMethod : ArrowKeyMovementMethod() {
4747
return true
4848
}
4949

50-
// get the character's position. This may be the left or the right edge of the character so, find the
51-
// other edge by inspecting nearby characters (if they exist)
52-
val charX = layout.getPrimaryHorizontal(off)
53-
val charPrevX = if (off > 0) layout.getPrimaryHorizontal(off - 1) else charX
54-
val charNextX = if (off < text.length) layout.getPrimaryHorizontal(off + 1) else charX
50+
// If we find that the touch event was on a link, then, we handle it and return immediately.
51+
if (handleLinkTouchEvent(widget = widget, text = text, event = event).handled) {
52+
return true
53+
}
54+
}
55+
56+
return super.onTouchEvent(widget, text, event)
57+
}
58+
59+
fun handleLinkTouchEvent(widget: TextView, text: Spannable, event: MotionEvent): LinkTouchEventResult {
60+
var x = event.x.toInt()
61+
var y = event.y.toInt()
62+
63+
x -= widget.totalPaddingLeft
64+
y -= widget.totalPaddingTop
5565

56-
val lineRect = Rect()
57-
layout.getLineBounds(line, lineRect)
66+
x += widget.scrollX
67+
y += widget.scrollY
5868

59-
val clickedWithinLineHeight = y >= lineRect.top && y <= lineRect.bottom
60-
val clickedOnSpanToTheLeftOfCursor = x.toFloat() in charPrevX..charX
61-
val clickedOnSpanToTheRightOfCursor = x.toFloat() in charX..charNextX
69+
val layout = widget.layout
70+
val line = layout.getLineForVertical(y)
71+
val off = layout.getOffsetForHorizontal(line, x.toFloat())
6272

63-
val clickedOnSpan = clickedWithinLineHeight &&
64-
(clickedOnSpanToTheLeftOfCursor || clickedOnSpanToTheRightOfCursor)
73+
// get the character's position. This may be the left or the right edge of the character so, find the
74+
// other edge by inspecting nearby characters (if they exist)
75+
val charX = layout.getPrimaryHorizontal(off)
76+
val charPrevX = if (off > 0) layout.getPrimaryHorizontal(off - 1) else charX
77+
val charNextX = if (off < text.length) layout.getPrimaryHorizontal(off + 1) else charX
6578

66-
val clickedSpanBordersAnotherOne = (text.getSpans(off, off, ClickableSpan::class.java).size == 1 &&
67-
text.getSpans(off + 1, off + 1, ClickableSpan::class.java).isNotEmpty())
79+
val lineRect = Rect()
80+
layout.getLineBounds(line, lineRect)
6881

69-
val isClickedSpanAmbiguous = text.getSpans(off, off, ClickableSpan::class.java).size > 1
82+
val clickedWithinLineHeight = y >= lineRect.top && y <= lineRect.bottom
83+
val clickedOnSpanToTheLeftOfCursor = x.toFloat() in charPrevX..charX
84+
val clickedOnSpanToTheRightOfCursor = x.toFloat() in charX..charNextX
7085

71-
val failedToPinpointClickedSpan = (isClickedSpanAmbiguous || clickedSpanBordersAnotherOne)
72-
&& !clickedOnSpanToTheLeftOfCursor && !clickedOnSpanToTheRightOfCursor
86+
val clickedOnSpan = clickedWithinLineHeight &&
87+
(clickedOnSpanToTheLeftOfCursor || clickedOnSpanToTheRightOfCursor)
7388

74-
var link: ClickableSpan? = null
89+
val clickedSpanBordersAnotherOne = (text.getSpans(off, off, ClickableSpan::class.java).size == 1 &&
90+
text.getSpans(off + 1, off + 1, ClickableSpan::class.java).isNotEmpty())
7591

76-
if (clickedOnSpan) {
77-
if (isClickedSpanAmbiguous) {
78-
if (clickedOnSpanToTheLeftOfCursor) {
79-
link = text.getSpans(off, off, ClickableSpan::class.java)[0]
80-
} else if (clickedOnSpanToTheRightOfCursor) {
81-
link = text.getSpans(off, off, ClickableSpan::class.java)[1]
82-
}
92+
val isClickedSpanAmbiguous = text.getSpans(off, off, ClickableSpan::class.java).size > 1
93+
94+
val failedToPinpointClickedSpan = (isClickedSpanAmbiguous || clickedSpanBordersAnotherOne)
95+
&& !clickedOnSpanToTheLeftOfCursor && !clickedOnSpanToTheRightOfCursor
96+
97+
var link: ClickableSpan? = null
98+
99+
if (clickedOnSpan) {
100+
link = if (isClickedSpanAmbiguous) {
101+
if (clickedOnSpanToTheLeftOfCursor) {
102+
text.getSpans(off, off, ClickableSpan::class.java)[0]
83103
} else {
84-
link = text.getSpans(off, off, ClickableSpan::class.java).firstOrNull()
104+
text.getSpans(off, off, ClickableSpan::class.java)[1]
85105
}
86-
} else if (failedToPinpointClickedSpan) {
87-
link = text.getSpans(off, off, ClickableSpan::class.java).firstOrNull { text.getSpanStart(it) == off }
106+
} else {
107+
text.getSpans(off, off, ClickableSpan::class.java).firstOrNull()
88108
}
109+
} else if (failedToPinpointClickedSpan) {
110+
link = text.getSpans(off, off, ClickableSpan::class.java).firstOrNull { text.getSpanStart(it) == off }
111+
}
89112

90-
if (link != null) {
91-
if (link is AztecMediaClickableSpan || link is UnknownClickableSpan) {
92-
link.onClick(widget)
93-
return true
94-
} else if (link is AztecURLSpan && isLinkTapEnabled) {
95-
linkTappedListenerRef.get()?.onLinkTapped(widget, link.url) ?: link.onClick(widget)
96-
return true
97-
}
113+
if (link != null) {
114+
if (link is AztecMediaClickableSpan || link is UnknownClickableSpan) {
115+
link.onClick(widget)
116+
return LinkTouchEventResult(true)
117+
} else if (link is AztecURLSpan && isLinkTapEnabled) {
118+
linkTappedListenerRef.get()?.onLinkTapped(widget, link.url) ?: link.onClick(widget)
119+
return LinkTouchEventResult(true)
98120
}
99121
}
100122

101-
return super.onTouchEvent(widget, text, event)
123+
return LinkTouchEventResult(false)
102124
}
103125
}
126+
127+
@JvmInline
128+
value class LinkTouchEventResult(val handled: Boolean)

0 commit comments

Comments
 (0)