feat: Enhance Protocol with additional packet types and integrate AppleEmojiText for improved emoji display
This commit is contained in:
@@ -33,8 +33,8 @@ class AppleEmojiEditTextView @JvmOverloads constructor(
|
||||
private var isUpdating = false
|
||||
|
||||
companion object {
|
||||
// Regex для эмодзи
|
||||
private val EMOJI_PATTERN = Pattern.compile(
|
||||
// Regex для эмодзи - public для доступа из других компонентов
|
||||
val EMOJI_PATTERN = Pattern.compile(
|
||||
"[\\x{1F600}-\\x{1F64F}]|" + // Emoticons
|
||||
"[\\x{1F300}-\\x{1F5FF}]|" + // Misc Symbols and Pictographs
|
||||
"[\\x{1F680}-\\x{1F6FF}]|" + // Transport and Map
|
||||
@@ -217,3 +217,93 @@ fun AppleEmojiTextField(
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* TextView с Apple эмодзи (для отображения, не редактирования)
|
||||
*/
|
||||
@Composable
|
||||
fun AppleEmojiText(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier,
|
||||
color: androidx.compose.ui.graphics.Color = androidx.compose.ui.graphics.Color.White,
|
||||
fontSize: androidx.compose.ui.unit.TextUnit = androidx.compose.ui.unit.TextUnit.Unspecified
|
||||
) {
|
||||
val fontSizeValue = if (fontSize == androidx.compose.ui.unit.TextUnit.Unspecified) 15f
|
||||
else fontSize.value
|
||||
|
||||
AndroidView(
|
||||
factory = { ctx ->
|
||||
AppleEmojiTextView(ctx).apply {
|
||||
setTextColor(color.toArgb())
|
||||
setTextSize(fontSizeValue)
|
||||
}
|
||||
},
|
||||
update = { view ->
|
||||
view.setTextWithEmojis(text)
|
||||
view.setTextColor(color.toArgb())
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Apple Emoji TextView - для отображения текста с PNG эмодзи
|
||||
*/
|
||||
class AppleEmojiTextView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = android.R.attr.textViewStyle
|
||||
) : android.widget.TextView(context, attrs, defStyleAttr) {
|
||||
|
||||
companion object {
|
||||
private val EMOJI_PATTERN = AppleEmojiEditTextView.EMOJI_PATTERN
|
||||
private val bitmapCache = LruCache<String, Bitmap>(100)
|
||||
}
|
||||
|
||||
fun setTextWithEmojis(text: String) {
|
||||
val spannable = SpannableStringBuilder(text)
|
||||
val matcher = EMOJI_PATTERN.matcher(text)
|
||||
|
||||
while (matcher.find()) {
|
||||
val emoji = matcher.group()
|
||||
val unified = emojiToUnified(emoji)
|
||||
val bitmap = loadEmojiBitmap(unified)
|
||||
|
||||
if (bitmap != null) {
|
||||
val size = (textSize * 1.2).toInt()
|
||||
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true)
|
||||
val drawable = BitmapDrawable(resources, scaledBitmap)
|
||||
drawable.setBounds(0, 0, size, size)
|
||||
|
||||
val span = ImageSpan(drawable, ImageSpan.ALIGN_BASELINE)
|
||||
spannable.setSpan(span, matcher.start(), matcher.end(),
|
||||
android.text.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
|
||||
setText(spannable)
|
||||
}
|
||||
|
||||
private fun loadEmojiBitmap(unified: String): Bitmap? {
|
||||
bitmapCache.get(unified)?.let { return it }
|
||||
|
||||
return try {
|
||||
val path = "emoji/$unified.png"
|
||||
val inputStream = context.assets.open(path)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream.close()
|
||||
bitmap?.let { bitmapCache.put(unified, it) }
|
||||
bitmap
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun emojiToUnified(emoji: String): String {
|
||||
return emoji.codePoints()
|
||||
.filter { it != 0xFE0F }
|
||||
.mapToObj { String.format("%04x", it) }
|
||||
.toList()
|
||||
.joinToString("-")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user