Continous Send bug fixes

This commit is contained in:
DarkKnight2122
2026-04-23 13:20:52 +05:30
parent 335cc00dfb
commit fb94a2e8a3
4 changed files with 98 additions and 50 deletions

View File

@@ -2570,7 +2570,8 @@
"platform_indicator": "يضيف أيقونة المنصة التي تم إرسال الوسيط منها (مثل Android، iOS، Web)", "platform_indicator": "يضيف أيقونة المنصة التي تم إرسال الوسيط منها (مثل Android، iOS، Web)",
"location_indicator": "يضيف أيقونة \ud83d\udccd للـ snaps عندما يتم إرسالها مع تمكين الموقع", "location_indicator": "يضيف أيقونة \ud83d\udccd للـ snaps عندما يتم إرسالها مع تمكين الموقع",
"ovf_editor_indicator": "يشير إلى ما إذا كان snap قد تم إرساله باستخدام محرر OVF", "ovf_editor_indicator": "يشير إلى ما إذا كان snap قد تم إرساله باستخدام محرر OVF",
"director_mode_indicator": "يضيف أيقونة \u270f\ufe0f للـ snaps عندما يتم إرسالها باستخدام وضع المخرج، والذي يمكن استخدامه لإرسال صور المعرض كـ snaps" "director_mode_indicator": "يضيف أيقونة \u270f\ufe0f للـ snaps عندما يتم إرسالها باستخدام وضع المخرج، والذي يمكن استخدامه لإرسال صور المعرض كـ snaps",
"memories_indicator": "إضافة رمز \uD83D\uDCD6 للسنابات التي تم إعادة إرسالها من الذكريات بدلاً من التقاطها بالكاميرا الحية"
}, },
"auto_mark_as_read": { "auto_mark_as_read": {
"conversation_read": "وضع علامة مقروء على المحادثة عند إرسال رسالة", "conversation_read": "وضع علامة مقروء على المحادثة عند إرسال رسالة",

View File

@@ -3259,7 +3259,8 @@
"platform_indicator": "Adds the platform icon from which a media was sent (e.g. Android, iOS, Web)", "platform_indicator": "Adds the platform icon from which a media was sent (e.g. Android, iOS, Web)",
"location_indicator": "Adds a \ud83d\udccd icon to snaps when they have been sent with location enabled", "location_indicator": "Adds a \ud83d\udccd icon to snaps when they have been sent with location enabled",
"ovf_editor_indicator": "Indicates if a snap has been sent using OVF Editor", "ovf_editor_indicator": "Indicates if a snap has been sent using OVF Editor",
"director_mode_indicator": "Adds a \u270f\ufe0f icon to snaps when they have been sent using Director Mode, which can be used to send gallery images as snaps" "director_mode_indicator": "Adds a \u270f\ufe0f icon to snaps when they have been sent using Director Mode, which can be used to send gallery images as snaps",
"memories_indicator": "Adds a \ud83d\udcd6 icon to snaps that were re-sent from Memories instead of being captured with the live camera"
}, },
"auto_mark_as_read": { "auto_mark_as_read": {
"conversation_read": "Mark conversation as read when sending a message", "conversation_read": "Mark conversation as read when sending a message",

View File

@@ -57,7 +57,7 @@ class UserInterfaceTweaks : ConfigContainer() {
val oldBitmojiSelfie = unique("old_bitmoji_selfie", "2d", "3d") { requireCleanCache() } val oldBitmojiSelfie = unique("old_bitmoji_selfie", "2d", "3d") { requireCleanCache() }
val disableSpotlight = boolean("disable_spotlight") { requireRestart() } val disableSpotlight = boolean("disable_spotlight") { requireRestart() }
val verticalStoryViewer = boolean("vertical_story_viewer") { requireRestart() } val verticalStoryViewer = boolean("vertical_story_viewer") { requireRestart() }
val messageIndicators = multiple("message_indicators", "encryption_indicator", "platform_indicator", "location_indicator", "ovf_editor_indicator", "director_mode_indicator") { requireRestart() } val messageIndicators = multiple("message_indicators", "encryption_indicator", "platform_indicator", "location_indicator", "ovf_editor_indicator", "director_mode_indicator", "memories_indicator") { requireRestart() }
val stealthModeIndicator = boolean("stealth_mode_indicator") { requireRestart() } val stealthModeIndicator = boolean("stealth_mode_indicator") { requireRestart() }
val editTextOverride = multiple("edit_text_override", "multi_line_chat_input", "bypass_text_input_limit") { val editTextOverride = multiple("edit_text_override", "multi_line_chat_input", "bypass_text_input_limit") {
requireRestart(); addNotices(FeatureNotice.BAN_RISK, FeatureNotice.INTERNAL_BEHAVIOR) requireRestart(); addNotices(FeatureNotice.BAN_RISK, FeatureNotice.INTERNAL_BEHAVIOR)

View File

@@ -8,23 +8,69 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.filled.*
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.getValue import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import me.eternal.purrfectsnap.common.data.ContentType import me.eternal.purrfectsnap.common.data.ContentType
import me.eternal.purrfectsnap.common.ui.createComposeView import me.eternal.purrfectsnap.common.ui.createComposeView
import me.eternal.purrfectsnap.common.ui.rememberAsyncMutableState
import me.eternal.purrfectsnap.common.util.protobuf.ProtoReader import me.eternal.purrfectsnap.common.util.protobuf.ProtoReader
import me.eternal.purrfectsnap.core.event.events.impl.BindViewEvent import me.eternal.purrfectsnap.core.event.events.impl.BindViewEvent
import me.eternal.purrfectsnap.core.features.Feature import me.eternal.purrfectsnap.core.features.Feature
import me.eternal.purrfectsnap.core.ui.AppleLogo import me.eternal.purrfectsnap.core.ui.AppleLogo
import kotlin.random.Random import kotlin.random.Random
@Composable
private fun GradientIcon(
imageVector: ImageVector,
brush: Brush,
size: androidx.compose.ui.unit.Dp = 16.dp
) {
Image(
imageVector = imageVector,
contentDescription = null,
colorFilter = ColorFilter.tint(Color.White),
modifier = Modifier
.size(size)
.graphicsLayer(alpha = 0.99f)
.drawWithContent {
drawContent()
drawRect(brush = brush, blendMode = BlendMode.SrcAtop)
}
)
}
@Composable
private fun GradientText(
text: String,
brush: Brush,
fontWeight: FontWeight,
fontSize: androidx.compose.ui.unit.TextUnit
) {
Text(
text = text,
color = Color.White,
fontWeight = fontWeight,
fontSize = fontSize,
modifier = Modifier
.graphicsLayer(alpha = 0.99f)
.drawWithContent {
drawContent()
drawRect(brush = brush, blendMode = BlendMode.SrcAtop)
}
)
}
class MessageIndicators : Feature("Message Indicators") { class MessageIndicators : Feature("Message Indicators") {
override fun init() { override fun init() {
val messageIndicatorsConfig = context.config.userInterface.messageIndicators.getNullable() ?: return val messageIndicatorsConfig = context.config.userInterface.messageIndicators.getNullable() ?: return
@@ -35,96 +81,96 @@ class MessageIndicators : Feature("Message Indicators") {
val appleLogo = AppleLogo val appleLogo = AppleLogo
context.event.subscribe(BindViewEvent::class) { event -> context.event.subscribe(BindViewEvent::class) { event ->
event.chatMessage { _, _ -> event.chatMessage { conversationId, _ ->
val view = event.view as? ViewGroup ?: return@subscribe val view = event.view as? ViewGroup ?: return@subscribe
view.findViewWithTag<View>(messageInfoTag)?.let { view.removeView(it) } view.findViewWithTag<View>(messageInfoTag)?.let { view.removeView(it) }
val message = event.databaseMessage ?: return@chatMessage val message = event.databaseMessage ?: return@chatMessage
if (message.contentType != ContentType.SNAP.id && message.contentType != ContentType.EXTERNAL_MEDIA.id) return@chatMessage if (message.contentType != ContentType.SNAP.id && message.contentType != ContentType.EXTERNAL_MEDIA.id) return@chatMessage
if (message.senderId == context.database.myUserId) return@chatMessage
val reader = ProtoReader(message.messageContent ?: return@chatMessage) val reader = ProtoReader(message.messageContent ?: return@chatMessage)
val isGroupConversation = (context.database.getConversationParticipants(conversationId)?.size ?: 0) > 2
createComposeView(event.view.context) { createComposeView(event.view.context) {
val lockBrush = Brush.linearGradient(listOf(Color(0xFF4CD471), Color(0xFF00B8D9)))
val locationBrush = Brush.linearGradient(listOf(Color(0xFFFF4B5C), Color(0xFFFFB74D)))
val androidBrush = Brush.linearGradient(listOf(Color(0xFF3DDC84), Color(0xFFA5E635)))
val appleBrush = Brush.linearGradient(listOf(Color(0xFFFFFFFF), Color(0xFF94A3B8)))
val webBrush = Brush.linearGradient(listOf(Color(0xFF4FC3F7), Color(0xFF00E5FF)))
val directorBrush = Brush.linearGradient(listOf(Color(0xFFFFB74D), Color(0xFFFF5E3A)))
val ovfBrush = Brush.linearGradient(listOf(Color(0xFFFF5CA8), Color(0xFFA64CFF)))
val memoriesBrush = Brush.linearGradient(listOf(Color(0xFFFFE066), Color(0xFFFFB300)))
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(50.dp) .height(50.dp)
.padding(top = 4.dp, end = 1.dp), .padding(top = 6.dp),
contentAlignment = Alignment.TopEnd contentAlignment = Alignment.TopCenter
) { ) {
val hasEncryption by rememberAsyncMutableState(defaultValue = false) { val hasEncryption = remember(reader, isGroupConversation) {
if (reader.containsPath(4, 4, 1, 1) if (reader.containsPath(4, 4, 1, 1)
|| reader.containsPath(4, 4, 1, 1, 1) || reader.containsPath(4, 4, 1, 1, 1)
|| reader.getByteArray(4, 3, 3) != null || reader.getByteArray(4, 3, 3) != null
|| reader.containsPath(3, 99, 3)) { || reader.containsPath(3, 99, 3)) {
return@rememberAsyncMutableState true return@remember true
} }
if (!reader.containsPath(3, 99, 5, 1)) return@rememberAsyncMutableState false if (isGroupConversation) return@remember false
reader.containsPath(4, 5, 1, 3, 1) if (reader.containsPath(4, 5, 1, 3, 1)) return@remember true
|| reader.getVarInt(4, 5, 1, 3, 2, 9) == 1L reader.getVarInt(4, 5, 1, 3, 2, 9) in setOf(1L, 3L)
} }
val sentFromIosDevice by rememberAsyncMutableState(defaultValue = false) { val sentFromIosDevice = remember(reader) {
if (reader.containsPath(4, 4, 3)) !reader.containsPath(4, 4, 3, 3, 17) else reader.getVarInt(4, 4, 11, 17, 7) != null if (reader.containsPath(4, 4, 3)) !reader.containsPath(4, 4, 3, 3, 17) else reader.getVarInt(4, 4, 11, 17, 7) != null
} }
val sentFromWebApp by rememberAsyncMutableState(defaultValue = false) { val sentFromWebApp = remember(reader) {
reader.getVarInt(4, 4, *(if (reader.containsPath(4, 4, 3)) intArrayOf(3, 3, 22, 1) else intArrayOf(11, 22, 1))) == 7L reader.getVarInt(4, 4, *(if (reader.containsPath(4, 4, 3)) intArrayOf(3, 3, 22, 1) else intArrayOf(11, 22, 1))) == 7L
} }
val sentWithLocation by rememberAsyncMutableState(defaultValue = false) { val sentWithLocation = remember(reader) {
reader.getVarInt(4, 4, 11, 17, 5) != null reader.getVarInt(4, 4, 11, 17, 5) != null
} }
val sentUsingOvfEditor by rememberAsyncMutableState(defaultValue = false) { val sentUsingOvfEditor = remember(reader) {
(reader.getString(4, 4, 11, 12, 1) ?: reader.getString(4, 4, 11, 13, 4, 1, 2, 12, 20, 1)) == "c13129f7-fe4a-44c4-9b9d-e0b26fee8f82" (reader.getString(4, 4, 11, 12, 1) ?: reader.getString(4, 4, 11, 13, 4, 1, 2, 12, 20, 1)) == "c13129f7-fe4a-44c4-9b9d-e0b26fee8f82"
} }
val sentUsingDirectorMode by rememberAsyncMutableState(defaultValue = false) { val sentUsingDirectorMode = remember(reader) {
reader.followPath(4, 4, 11, 28)?.let { reader.followPath(4, 4, 11, 28)?.let {
(it.getVarInt(1) to it.getVarInt(2)) == (0L to 0L) (it.getVarInt(1) to it.getVarInt(2)) == (0L to 0L)
} == true || reader.getByteArray(4, 4, 11, 13, 4, 1, 2, 12, 27, 1) != null } == true || reader.getByteArray(4, 4, 11, 13, 4, 1, 2, 12, 27, 1) != null
} }
val sentFromMemories = remember(reader) {
reader.getVarInt(4, 18) != null
|| reader.getString(4, 5, 1, 2)?.contains("/h/") == true
}
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) { ) {
if (sentWithLocation && messageIndicatorsConfig.contains("location_indicator")) { if (sentWithLocation && messageIndicatorsConfig.contains("location_indicator")) {
Image( GradientIcon(Icons.Default.LocationOn, locationBrush)
imageVector = Icons.Default.LocationOn,
colorFilter = ColorFilter.tint(Color.Green),
contentDescription = null,
modifier = Modifier.size(15.dp)
)
} }
if (messageIndicatorsConfig.contains("platform_indicator")) { if (messageIndicatorsConfig.contains("platform_indicator")) {
Image( val (platformIcon, platformBrush) = when {
imageVector = when { sentFromWebApp -> Icons.Default.Laptop to webBrush
sentFromWebApp -> Icons.Default.Laptop sentFromIosDevice -> appleLogo to appleBrush
sentFromIosDevice -> appleLogo else -> Icons.Default.Android to androidBrush
else -> Icons.Default.Android }
}, GradientIcon(platformIcon, platformBrush)
colorFilter = ColorFilter.tint(Color.Green),
contentDescription = null,
modifier = Modifier.size(15.dp)
)
} }
if (hasEncryption && messageIndicatorsConfig.contains("encryption_indicator")) { if (hasEncryption && messageIndicatorsConfig.contains("encryption_indicator")) {
Image( GradientIcon(Icons.Default.Lock, lockBrush)
imageVector = Icons.Default.Lock,
colorFilter = ColorFilter.tint(Color.Green),
contentDescription = null,
modifier = Modifier.size(15.dp)
)
} }
if (sentUsingDirectorMode && messageIndicatorsConfig.contains("director_mode_indicator")) { if (sentUsingDirectorMode && messageIndicatorsConfig.contains("director_mode_indicator")) {
Image( GradientIcon(Icons.Default.Edit, directorBrush)
imageVector = Icons.Default.Edit, }
colorFilter = ColorFilter.tint(Color.Red), if (sentFromMemories && messageIndicatorsConfig.contains("memories_indicator")) {
contentDescription = null, GradientIcon(Icons.Default.HistoryEdu, memoriesBrush)
modifier = Modifier.size(15.dp)
)
} }
if (sentUsingOvfEditor && messageIndicatorsConfig.contains("ovf_editor_indicator")) { if (sentUsingOvfEditor && messageIndicatorsConfig.contains("ovf_editor_indicator")) {
Text( GradientText(
text = "OVF", text = "OVF",
color = Color.Red, brush = ovfBrush,
fontWeight = FontWeight.ExtraBold, fontWeight = FontWeight.ExtraBold,
fontSize = 10.sp, fontSize = 11.sp
) )
} }
} }