feat: Enhance Protocol with additional packet types and integrate AppleEmojiText for improved emoji display

This commit is contained in:
k1ngsterr1
2026-01-10 22:25:26 +05:00
parent 6014d23d69
commit 9baa7f444a
4 changed files with 105 additions and 5 deletions

View File

@@ -76,7 +76,11 @@ class Protocol(
0x02 to { PacketResult() }, 0x02 to { PacketResult() },
0x03 to { PacketSearch() }, 0x03 to { PacketSearch() },
0x04 to { PacketOnlineSubscribe() }, 0x04 to { PacketOnlineSubscribe() },
0x05 to { PacketOnlineState() } 0x05 to { PacketOnlineState() },
0x06 to { PacketMessage() },
0x07 to { PacketRead() },
0x08 to { PacketDelivery() },
0x0B to { PacketTyping() }
) )
init { init {

View File

@@ -49,6 +49,7 @@ import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.components.VerifiedBadge import com.rosetta.messenger.ui.components.VerifiedBadge
import com.rosetta.messenger.ui.components.AppleEmojiPickerPanel import com.rosetta.messenger.ui.components.AppleEmojiPickerPanel
import com.rosetta.messenger.ui.components.AppleEmojiTextField import com.rosetta.messenger.ui.components.AppleEmojiTextField
import com.rosetta.messenger.ui.components.AppleEmojiText
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@@ -421,7 +422,7 @@ private fun MessageBubble(
.padding(horizontal = 12.dp, vertical = 8.dp) .padding(horizontal = 12.dp, vertical = 8.dp)
) { ) {
Column { Column {
Text( AppleEmojiText(
text = message.text, text = message.text,
color = textColor, color = textColor,
fontSize = 15.sp fontSize = 15.sp

View File

@@ -121,9 +121,13 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
* Открыть диалог * Открыть диалог
*/ */
fun openDialog(publicKey: String) { fun openDialog(publicKey: String) {
if (opponentKey == publicKey) {
ProtocolManager.addLog("💬 Dialog already open: ${publicKey.take(16)}...")
return
}
opponentKey = publicKey opponentKey = publicKey
_messages.value = emptyList() _messages.value = emptyList()
ProtocolManager.addLog("💬 Dialog: ${publicKey.take(16)}...") ProtocolManager.addLog("💬 Dialog opened: ${publicKey.take(16)}...")
} }
/** /**
@@ -176,6 +180,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
_inputText.value = "" _inputText.value = ""
ProtocolManager.addLog("📤 Send: \"${text.take(20)}...\"") ProtocolManager.addLog("📤 Send: \"${text.take(20)}...\"")
ProtocolManager.addLog("📋 Messages count: ${_messages.value.size}")
// 2. Отправка в фоне // 2. Отправка в фоне
viewModelScope.launch { viewModelScope.launch {

View File

@@ -33,8 +33,8 @@ class AppleEmojiEditTextView @JvmOverloads constructor(
private var isUpdating = false private var isUpdating = false
companion object { companion object {
// Regex для эмодзи // Regex для эмодзи - public для доступа из других компонентов
private val EMOJI_PATTERN = Pattern.compile( val EMOJI_PATTERN = Pattern.compile(
"[\\x{1F600}-\\x{1F64F}]|" + // Emoticons "[\\x{1F600}-\\x{1F64F}]|" + // Emoticons
"[\\x{1F300}-\\x{1F5FF}]|" + // Misc Symbols and Pictographs "[\\x{1F300}-\\x{1F5FF}]|" + // Misc Symbols and Pictographs
"[\\x{1F680}-\\x{1F6FF}]|" + // Transport and Map "[\\x{1F680}-\\x{1F6FF}]|" + // Transport and Map
@@ -217,3 +217,93 @@ fun AppleEmojiTextField(
modifier = modifier 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("-")
}
}