react-native-advanced-text 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -32,6 +32,7 @@ class AdvancedTextView : TextView {
|
|
|
32
32
|
private var lastSelectedText: String = ""
|
|
33
33
|
private var customActionMode: ActionMode? = null
|
|
34
34
|
private var currentText: String = ""
|
|
35
|
+
private var textColor: String = "#000000"
|
|
35
36
|
|
|
36
37
|
// Cache for word positions to avoid recalculating
|
|
37
38
|
private var wordPositions: List<WordPosition> = emptyList()
|
|
@@ -41,53 +42,58 @@ class AdvancedTextView : TextView {
|
|
|
41
42
|
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { init() }
|
|
42
43
|
|
|
43
44
|
private fun init() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
45
|
+
Log.d(TAG, "AdvancedTextView initialized")
|
|
46
|
+
|
|
47
|
+
textSize = 16f
|
|
48
|
+
setPadding(16, 16, 16, 16)
|
|
49
|
+
|
|
50
|
+
movementMethod = ClickableMovementMethod.getInstance()
|
|
51
|
+
isClickable = false
|
|
52
|
+
isLongClickable = false
|
|
53
|
+
|
|
54
|
+
setTextIsSelectable(true)
|
|
55
|
+
|
|
56
|
+
customSelectionActionModeCallback = object : ActionMode.Callback {
|
|
57
|
+
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
|
58
|
+
customActionMode = mode
|
|
59
|
+
return true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
|
63
|
+
menu?.clear()
|
|
64
|
+
val selectionStart = selectionStart
|
|
65
|
+
val selectionEnd = selectionEnd
|
|
66
|
+
|
|
67
|
+
if (selectionStart >= 0 && selectionEnd >= 0 && selectionStart != selectionEnd) {
|
|
68
|
+
lastSelectedText = text.subSequence(selectionStart, selectionEnd).toString()
|
|
69
|
+
menuOptions.forEachIndexed { index, option ->
|
|
70
|
+
menu?.add(0, index, index, option)
|
|
71
|
+
}
|
|
72
|
+
sendSelectionEvent(lastSelectedText, "selection")
|
|
73
|
+
return true
|
|
74
|
+
}
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
|
79
|
+
item?.let {
|
|
80
|
+
sendSelectionEvent(lastSelectedText, it.title.toString())
|
|
81
|
+
mode?.finish()
|
|
82
|
+
return true
|
|
83
|
+
}
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override fun onDestroyActionMode(mode: ActionMode?) {
|
|
88
|
+
customActionMode = null
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
76
92
|
|
|
77
|
-
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
|
78
|
-
item?.let {
|
|
79
|
-
val menuItemText = it.title.toString()
|
|
80
|
-
sendSelectionEvent(lastSelectedText, menuItemText)
|
|
81
|
-
mode?.finish()
|
|
82
|
-
return true
|
|
83
|
-
}
|
|
84
|
-
return false
|
|
85
|
-
}
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
94
|
+
fun setAdvancedTextColor(colorInt: Int) {
|
|
95
|
+
textColor = String.format("#%06X", 0xFFFFFF and colorInt)
|
|
96
|
+
updateTextWithHighlights()
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
fun setAdvancedText(text: String) {
|
|
@@ -165,7 +171,7 @@ class AdvancedTextView : TextView {
|
|
|
165
171
|
// Apply indicator color
|
|
166
172
|
if (wordPos.index == indicatorWordIndex) {
|
|
167
173
|
spannableString.setSpan(
|
|
168
|
-
ForegroundColorSpan(Color.
|
|
174
|
+
ForegroundColorSpan(Color.parseColor(textColor)),
|
|
169
175
|
wordPos.start,
|
|
170
176
|
wordPos.end,
|
|
171
177
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
|
@@ -213,8 +219,8 @@ class AdvancedTextView : TextView {
|
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
private inner class WordClickableSpan(
|
|
216
|
-
|
|
217
|
-
|
|
222
|
+
private val wordIndex: Int,
|
|
223
|
+
private val word: String
|
|
218
224
|
) : ClickableSpan() {
|
|
219
225
|
|
|
220
226
|
override fun onClick(widget: View) {
|
|
@@ -231,6 +237,7 @@ class AdvancedTextView : TextView {
|
|
|
231
237
|
override fun updateDrawState(ds: TextPaint) {
|
|
232
238
|
super.updateDrawState(ds)
|
|
233
239
|
ds.isUnderlineText = false
|
|
240
|
+
ds.color = Color.parseColor(textColor)
|
|
234
241
|
}
|
|
235
242
|
}
|
|
236
243
|
|
|
@@ -86,7 +86,9 @@ class AdvancedTextViewManager : SimpleViewManager<AdvancedTextView>() {
|
|
|
86
86
|
@ReactProp(name = "color", customType = "Color")
|
|
87
87
|
fun setColor(view: AdvancedTextView?, color: Int?) {
|
|
88
88
|
android.util.Log.d(NAME, "setColor called with: $color")
|
|
89
|
-
|
|
89
|
+
if (color != null) {
|
|
90
|
+
view?.setAdvancedTextColor(color)
|
|
91
|
+
}
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
@ReactProp(name = "fontSize")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
package com.advancedtext
|
|
2
|
+
|
|
3
|
+
import android.text.Layout
|
|
4
|
+
import android.text.Selection
|
|
5
|
+
import android.text.Spannable
|
|
6
|
+
import android.text.method.BaseMovementMethod
|
|
7
|
+
import android.text.style.ClickableSpan
|
|
8
|
+
import android.view.MotionEvent
|
|
9
|
+
import android.widget.TextView
|
|
10
|
+
|
|
11
|
+
class ClickableMovementMethod : BaseMovementMethod() {
|
|
12
|
+
|
|
13
|
+
companion object {
|
|
14
|
+
private var sInstance: ClickableMovementMethod? = null
|
|
15
|
+
|
|
16
|
+
fun getInstance(): ClickableMovementMethod {
|
|
17
|
+
if (sInstance == null) {
|
|
18
|
+
sInstance = ClickableMovementMethod()
|
|
19
|
+
}
|
|
20
|
+
return sInstance!!
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun canSelectArbitrarily(): Boolean = false
|
|
25
|
+
|
|
26
|
+
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
|
|
27
|
+
val action = event.actionMasked
|
|
28
|
+
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
|
|
29
|
+
|
|
30
|
+
var x = (event.x - widget.totalPaddingLeft + widget.scrollX).toInt()
|
|
31
|
+
var y = (event.y - widget.totalPaddingTop + widget.scrollY).toInt()
|
|
32
|
+
|
|
33
|
+
val layout: Layout = widget.layout
|
|
34
|
+
val links: Array<ClickableSpan>? = if (y < 0 || y > layout.height) {
|
|
35
|
+
null
|
|
36
|
+
} else {
|
|
37
|
+
val line = layout.getLineForVertical(y)
|
|
38
|
+
if (x < layout.getLineLeft(line) || x > layout.getLineRight(line)) null
|
|
39
|
+
else {
|
|
40
|
+
val offset = layout.getOffsetForHorizontal(line, x.toFloat())
|
|
41
|
+
buffer.getSpans(offset, offset, ClickableSpan::class.java)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!links.isNullOrEmpty()) {
|
|
46
|
+
if (action == MotionEvent.ACTION_UP) links[0].onClick(widget)
|
|
47
|
+
else Selection.setSelection(buffer, buffer.getSpanStart(links[0]), buffer.getSpanEnd(links[0]))
|
|
48
|
+
return true
|
|
49
|
+
} else {
|
|
50
|
+
Selection.removeSelection(buffer)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override fun initialize(widget: TextView, text: Spannable) {
|
|
57
|
+
Selection.removeSelection(text)
|
|
58
|
+
}
|
|
59
|
+
}
|
package/package.json
CHANGED