@@ -5,19 +5,27 @@ import android.content.ActivityNotFoundException
5
5
import android.content.ClipData
6
6
import android.content.ClipboardManager
7
7
import android.content.Intent
8
+ import android.graphics.Typeface
8
9
import android.net.Uri
9
10
import android.os.Bundle
11
+ import android.text.Spannable
12
+ import android.text.style.ForegroundColorSpan
13
+ import android.text.style.RelativeSizeSpan
14
+ import android.text.style.StyleSpan
15
+ import android.text.style.TypefaceSpan
10
16
import android.view.ContextMenu
11
17
import android.view.MenuItem
12
18
import android.view.MotionEvent
13
19
import android.view.View
14
20
import android.widget.AdapterView
21
+ import android.widget.EditText
15
22
import android.widget.Toast
16
23
import androidx.activity.result.contract.ActivityResultContracts
17
24
import androidx.core.content.FileProvider
18
25
import androidx.core.content.getSystemService
19
26
import androidx.core.content.res.ResourcesCompat
20
27
import androidx.core.os.bundleOf
28
+ import androidx.core.text.getSpans
21
29
import androidx.core.view.ViewCompat
22
30
import androidx.core.view.WindowInsetsAnimationCompat
23
31
import androidx.core.view.WindowInsetsCompat
@@ -50,6 +58,39 @@ import ltd.evilcorp.domain.tox.PublicKey
50
58
const val CONTACT_PUBLIC_KEY = " publicKey"
51
59
private const val MAX_CONFIRM_DELETE_STRING_LENGTH = 20
52
60
61
+ private inline fun <reified T : Any > clearStyle (e : Spannable ) {
62
+ for (span in e.getSpans<T >()) {
63
+ e.removeSpan(span)
64
+ }
65
+ }
66
+
67
+ private fun clearStyles (view : EditText ) {
68
+ val spannable = view.text
69
+ clearStyle<ForegroundColorSpan >(spannable)
70
+ clearStyle<RelativeSizeSpan >(spannable)
71
+ clearStyle<StyleSpan >(spannable)
72
+ clearStyle<TypefaceSpan >(spannable)
73
+ }
74
+
75
+ private fun applyStyle (
76
+ view : EditText ,
77
+ regex : Regex ,
78
+ typefaceStyle : Int ,
79
+ fontFamily : String = "",
80
+ size : Float = 1f,
81
+ ) {
82
+ val spannable = view.text
83
+ for (match in regex.findAll(spannable)) {
84
+ val start = match.range.first
85
+ val end = match.range.last + 1
86
+ spannable.setSpan(RelativeSizeSpan (size), start, end, Spannable .SPAN_EXCLUSIVE_EXCLUSIVE )
87
+ spannable.setSpan(StyleSpan (typefaceStyle), start, end, Spannable .SPAN_EXCLUSIVE_EXCLUSIVE )
88
+ if (fontFamily.isNotEmpty()) {
89
+ spannable.setSpan(TypefaceSpan (fontFamily), start, end, Spannable .SPAN_EXCLUSIVE_EXCLUSIVE )
90
+ }
91
+ }
92
+ }
93
+
53
94
class ChatFragment : BaseFragment <FragmentChatBinding >(FragmentChatBinding : :inflate) {
54
95
private val viewModel: ChatViewModel by viewModels { vmFactory }
55
96
@@ -265,6 +306,11 @@ class ChatFragment : BaseFragment<FragmentChatBinding>(FragmentChatBinding::infl
265
306
outgoingMessage.doAfterTextChanged {
266
307
viewModel.setTyping(outgoingMessage.text.isNotEmpty())
267
308
updateActions()
309
+ clearStyles(outgoingMessage)
310
+ applyStyle(outgoingMessage, Regex (" (?<!`)`[^`\n ]+?`(?!`)" ), Typeface .BOLD , " monospace" , 0.8f )
311
+ applyStyle(outgoingMessage, Regex (" (?<!\\ *)\\ *\\ *\\ *[^*\n ]+?\\ *\\ *\\ *(?!\\ *)" ), Typeface .BOLD_ITALIC )
312
+ applyStyle(outgoingMessage, Regex (" (?<!\\ *)\\ *\\ *[^*\n ]+?\\ *\\ *(?!\\ *)" ), Typeface .BOLD )
313
+ applyStyle(outgoingMessage, Regex (" (?<!\\ *)\\ *[^*\n ]+?\\ *(?!\\ *)" ), Typeface .ITALIC )
268
314
}
269
315
270
316
updateActions()
0 commit comments