Continous Send bug fixes
This commit is contained in:
@@ -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": "وضع علامة مقروء على المحادثة عند إرسال رسالة",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user