Commit 80cacca2 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Fix backspace deleting

parent 1023ed18
...@@ -223,8 +223,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiBottomPicker.OnEmojiClic ...@@ -223,8 +223,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiBottomPicker.OnEmojiClic
override fun onEmojiAdded(emoji: Emoji) { override fun onEmojiAdded(emoji: Emoji) {
val cursorPosition = text_message.selectionStart val cursorPosition = text_message.selectionStart
val text = text_message.text.insert(cursorPosition, emoji.shortname).toString() text_message.text.insert(cursorPosition, EmojiParser.parse(emoji.shortname))
text_message.content = EmojiParser.parse(text)
text_message.setSelection(cursorPosition + emoji.unicode.length) text_message.setSelection(cursorPosition + emoji.unicode.length)
KeyboardHelper.showSoftKeyboard(text_message) KeyboardHelper.showSoftKeyboard(text_message)
} }
...@@ -281,7 +280,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiBottomPicker.OnEmojiClic ...@@ -281,7 +280,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiBottomPicker.OnEmojiClic
button_add_reaction.setOnClickListener { button_add_reaction.setOnClickListener {
activity?.let { activity?.let {
KeyboardHelper.hideSoftKeyboard(it) KeyboardHelper.hideSoftKeyboard(it)
EmojiBottomPicker().show(it.supportFragmentManager, "EmojiBottomPicker") val emojiBottomPicker = EmojiBottomPicker()
text_message.apply {
addTextChangedListener(EmojiBottomPicker.EmojiTextWatcher(this))
}
emojiBottomPicker.show(it.supportFragmentManager, "EmojiBottomPicker")
} }
} }
} }
......
...@@ -49,7 +49,8 @@ var TextView.content: CharSequence ...@@ -49,7 +49,8 @@ var TextView.content: CharSequence
TextUtils.copySpansFrom(value, 0, value.length, Any::class.java, result, 0) TextUtils.copySpansFrom(value, 0, value.length, Any::class.java, result, 0)
text = result text = result
} else { } else {
text = value val result = EmojiParser.parse(value.toString()) as Spannable
text = result
} }
Markwon.scheduleDrawables(this) Markwon.scheduleDrawables(this)
Markwon.scheduleTableRows(this) Markwon.scheduleTableRows(this)
......
...@@ -7,12 +7,17 @@ import android.support.design.widget.BottomSheetDialog ...@@ -7,12 +7,17 @@ import android.support.design.widget.BottomSheetDialog
import android.support.design.widget.TabLayout import android.support.design.widget.TabLayout
import android.support.v4.app.DialogFragment import android.support.v4.app.DialogFragment
import android.support.v4.view.ViewPager import android.support.v4.view.ViewPager
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import java.util.concurrent.atomic.AtomicReference
import java.util.function.UnaryOperator
open class EmojiBottomPicker : DialogFragment() { open class EmojiBottomPicker : DialogFragment() {
...@@ -90,6 +95,50 @@ open class EmojiBottomPicker : DialogFragment() { ...@@ -90,6 +95,50 @@ open class EmojiBottomPicker : DialogFragment() {
return BottomSheetDialog(context!!, theme) return BottomSheetDialog(context!!, theme)
} }
class EmojiTextWatcher(val editor: EditText) : TextWatcher {
@Volatile private var emojiToRemove = mutableListOf<EmojiTypefaceSpan>()
override fun afterTextChanged(s: Editable) {
val message = editor.getEditableText()
// Commit the emoticons to be removed.
for (span in emojiToRemove.toList()) {
val start = message.getSpanStart(span)
val end = message.getSpanEnd(span)
// Remove the span
message.removeSpan(span)
// Remove the remaining emoticon text.
if (start != end) {
message.delete(start, end)
}
break
}
emojiToRemove.clear()
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
if (after < count) {
val end = start + count
val message = editor.getEditableText()
val list = message.getSpans(start, end, EmojiTypefaceSpan::class.java)
for (span in list) {
val spanStart = message.getSpanStart(span)
val spanEnd = message.getSpanEnd(span)
if (spanStart < end && spanEnd > start) {
// Add to remove list
emojiToRemove.add(span)
}
}
}
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
}
interface OnEmojiClickCallback { interface OnEmojiClickCallback {
/** /**
* Callback triggered after an emoji is selected on the picker. * Callback triggered after an emoji is selected on the picker.
......
...@@ -112,10 +112,10 @@ class EmojiLoader { ...@@ -112,10 +112,10 @@ class EmojiLoader {
/** /**
* Replace shortnames to unicode characters. * Replace shortnames to unicode characters.
*/ */
fun shortnameToUnicode(input: String, removeIfUnsupported: Boolean): String { fun shortnameToUnicode(input: CharSequence, removeIfUnsupported: Boolean): String {
val matcher = SHORTNAME_PATTERN.matcher(input) val matcher = SHORTNAME_PATTERN.matcher(input)
val supported = Build.VERSION.SDK_INT >= 16 val supported = Build.VERSION.SDK_INT >= 16
var result: String = input var result: String = input.toString()
while (matcher.find()) { while (matcher.find()) {
val unicode = shortNameToUnicode.get(":${matcher.group(1)}:") val unicode = shortNameToUnicode.get(":${matcher.group(1)}:")
...@@ -124,9 +124,9 @@ class EmojiLoader { ...@@ -124,9 +124,9 @@ class EmojiLoader {
} }
if (supported) { if (supported) {
result = input.replace(":" + matcher.group(1) + ":", unicode) result = result.replace(":" + matcher.group(1) + ":", unicode)
} else if (!supported && removeIfUnsupported) { } else if (!supported && removeIfUnsupported) {
result = input.replace(":" + matcher.group(1) + ":", "") result = result.replace(":" + matcher.group(1) + ":", "")
} }
} }
......
...@@ -10,10 +10,10 @@ class EmojiParser { ...@@ -10,10 +10,10 @@ class EmojiParser {
* Spannable. * Spannable.
* *
* @param text The text to parse * @param text The text to parse
* * smiley = D83D DE03
* @return A rendered Spannable containing any supported emoji. * @return A rendered Spannable containing any supported emoji.
*/ */
fun parse(text: String): CharSequence { fun parse(text: CharSequence): CharSequence {
val unicodedText = EmojiLoader.shortnameToUnicode(text, true) val unicodedText = EmojiLoader.shortnameToUnicode(text, true)
val spannableString = SpannableString.valueOf(unicodedText) val spannableString = SpannableString.valueOf(unicodedText)
// Look for groups of emojis, set a CustomTypefaceSpan with the emojione font // Look for groups of emojis, set a CustomTypefaceSpan with the emojione font
...@@ -32,14 +32,14 @@ class EmojiParser { ...@@ -32,14 +32,14 @@ class EmojiParser {
} else { } else {
if (inEmoji) { if (inEmoji) {
spannableString.setSpan(EmojiTypefaceSpan("sans-serif", EmojiLoader.cachedTypeface), spannableString.setSpan(EmojiTypefaceSpan("sans-serif", EmojiLoader.cachedTypeface),
emojiStart, offset, Spanned.SPAN_INCLUSIVE_INCLUSIVE) emojiStart, offset, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
} }
inEmoji = false inEmoji = false
} }
offset += count offset += count
if (offset >= length && inEmoji) { if (offset >= length && inEmoji) {
spannableString.setSpan(EmojiTypefaceSpan("sans-serif", EmojiLoader.cachedTypeface), spannableString.setSpan(EmojiTypefaceSpan("sans-serif", EmojiLoader.cachedTypeface),
emojiStart, offset, Spanned.SPAN_INCLUSIVE_INCLUSIVE) emojiStart, offset, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
} }
} }
return spannableString return spannableString
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment