commit 3d6d070b291cac933eb82f526d06767bea2deb18
parent 52addbe78063537fcc0b9704d9dc24faaaea4906
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun, 17 Mar 2024 00:08:08 +0100

feat(core): message indicators

Diffstat:
Mcommon/src/main/assets/lang/en_US.json | 11++++++++---
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt | 2+-
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/features/FeatureManager.kt | 2+-
Dcore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/FideliusIndicator.kt | 43-------------------------------------------
Acore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/MessageIndicators.kt | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/src/main/kotlin/me/rhunk/snapenhance/core/ui/ComposeIcons.kt | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 198 insertions(+), 48 deletions(-)

diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json @@ -336,9 +336,9 @@ "name": "Friend Feed Menu Bar", "description": "Enables the new Friend Feed Menu Bar" }, - "fidelius_indicator": { - "name": "Fidelius Indicator", - "description": "Adds a green circle next to messages that have been sent only to you" + "message_indicators": { + "name": "Message Indicators", + "description": "Adds specific indicators icons to messages\nNote: indicators might not be 100% accurate" }, "stealth_mode_indicator": { "name": "Stealth Mode Indicator", @@ -944,6 +944,11 @@ "read_contacts": "Read Contacts", "nearby_devices": "Nearby Devices", "phone_calls": "Phone Calls" + }, + "message_indicators": { + "encryption_indicator": "Adds a \uD83D\uDD12 icon next to messages that have been sent only to you", + "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" } } }, diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt @@ -47,7 +47,7 @@ class UserInterfaceTweaks : ConfigContainer() { val disableSpotlight = boolean("disable_spotlight") { requireRestart() } val hideSettingsGear = boolean("hide_settings_gear") { requireRestart() } val verticalStoryViewer = boolean("vertical_story_viewer") { requireRestart() } - val fideliusIndicator = boolean("fidelius_indicator") { requireRestart() } + val messageIndicators = multiple("message_indicators", "encryption_indicator", "platform_indicator", "location_indicator") { requireRestart() } val stealthModeIndicator = boolean("stealth_mode_indicator") { requireRestart() } val editTextOverride = multiple("edit_text_override", "multi_line_chat_input", "bypass_text_input_limit") { requireRestart(); addNotices(FeatureNotice.BAN_RISK, FeatureNotice.INTERNAL_BEHAVIOR) diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/FeatureManager.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/FeatureManager.kt @@ -112,7 +112,7 @@ class FeatureManager( DisableConfirmationDialogs(), MixerStories(), DisableComposerModules(), - FideliusIndicator(), + MessageIndicators(), EditTextOverride(), PreventForcedLogout(), SuspendLocationUpdates(), diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/FideliusIndicator.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/FideliusIndicator.kt @@ -1,42 +0,0 @@ -package me.rhunk.snapenhance.core.features.impl.ui - -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.drawable.ShapeDrawable -import android.graphics.drawable.shapes.Shape -import me.rhunk.snapenhance.common.data.ContentType -import me.rhunk.snapenhance.common.util.protobuf.ProtoReader -import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent -import me.rhunk.snapenhance.core.features.Feature -import me.rhunk.snapenhance.core.features.FeatureLoadParams -import me.rhunk.snapenhance.core.ui.addForegroundDrawable -import me.rhunk.snapenhance.core.ui.removeForegroundDrawable - -class FideliusIndicator : Feature("Fidelius Indicator", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) { - override fun onActivityCreate() { - if (!context.config.userInterface.fideliusIndicator.get()) return - - context.event.subscribe(BindViewEvent::class) { event -> - event.chatMessage { _, messageId -> - event.view.removeForegroundDrawable("fideliusIndicator") - - val message = context.database.getConversationMessageFromId(messageId.toLong()) ?: return@chatMessage - if (message.senderId == context.database.myUserId) return@chatMessage - if (message.contentType != ContentType.SNAP.id && message.contentType != ContentType.EXTERNAL_MEDIA.id) return@chatMessage - - if (!ProtoReader(message.messageContent ?: return@chatMessage).containsPath(4, 3, 3, 6)) return@chatMessage - - event.view.addForegroundDrawable("fideliusIndicator", ShapeDrawable(object: Shape() { - override fun draw(canvas: Canvas, paint: Paint) { - val margin = 25f - val radius = 15f - - canvas.drawCircle(margin + radius, canvas.height - margin - radius, radius, paint.apply { - color = 0xFF00FF00.toInt() - }) - } - })) - } - } - } -}- \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/MessageIndicators.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/MessageIndicators.kt @@ -0,0 +1,110 @@ +package me.rhunk.snapenhance.core.features.impl.ui + +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Android +import androidx.compose.material.icons.filled.Laptop +import androidx.compose.material.icons.filled.LocationOn +import androidx.compose.material.icons.filled.Lock +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.unit.dp +import me.rhunk.snapenhance.common.data.ContentType +import me.rhunk.snapenhance.common.ui.createComposeView +import me.rhunk.snapenhance.common.util.protobuf.ProtoReader +import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent +import me.rhunk.snapenhance.core.features.Feature +import me.rhunk.snapenhance.core.features.FeatureLoadParams +import me.rhunk.snapenhance.core.ui.AppleLogo +import me.rhunk.snapenhance.core.ui.removeForegroundDrawable +import kotlin.random.Random + +class MessageIndicators : Feature("Message Indicators", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) { + override fun onActivityCreate() { + val messageIndicatorsConfig = context.config.userInterface.messageIndicators.getNullable() ?: return + if (messageIndicatorsConfig.isEmpty()) return + + val messageInfoTag = Random.nextLong().toString() + val appleLogo = AppleLogo + + context.event.subscribe(BindViewEvent::class) { event -> + event.chatMessage { _, messageId -> + val parentLinearLayout = event.view.parent as? ViewGroup ?: return@subscribe + parentLinearLayout.findViewWithTag<View>(messageInfoTag)?.let { parentLinearLayout.removeView(it) } + + event.view.removeForegroundDrawable("messageIndicators") + + val message = context.database.getConversationMessageFromId(messageId.toLong()) ?: return@chatMessage + if (message.contentType != ContentType.SNAP.id && message.contentType != ContentType.EXTERNAL_MEDIA.id) return@chatMessage + val reader = ProtoReader(message.messageContent ?: return@chatMessage) + + val hasEncryption = if (reader.containsPath(4, 3)) reader.getByteArray(4, 3, 1) == null else false + val sentFromIosDevice = if (reader.containsPath(4, 4, 3)) !reader.containsPath(4, 4, 3, 3, 17) else reader.getVarInt(4, 4, 11, 17, 7) != null + val sentFromWebApp = reader.getVarInt(4, 4, *(if (reader.containsPath(4, 4, 3)) intArrayOf(3, 3, 22, 1) else intArrayOf(11, 22, 1))) == 7L + val sentWithLocation = reader.getVarInt(4, 4, 11, 17, 5) != null + + createComposeView(event.view.context) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp, end = 1.dp), + contentAlignment = Alignment.BottomEnd + ) { + Row { + if (messageIndicatorsConfig.contains("location_indicator")) { + if (sentWithLocation) { + Image( + imageVector = Icons.Default.LocationOn, + colorFilter = ColorFilter.tint(Color.Green), + contentDescription = null, + modifier = Modifier.size(15.dp) + ) + } + } + if (messageIndicatorsConfig.contains("platform_indicator")) { + Image( + imageVector = when { + sentFromWebApp -> Icons.Default.Laptop + sentFromIosDevice -> appleLogo + else -> Icons.Default.Android + }, + colorFilter = ColorFilter.tint(Color.Green), + contentDescription = null, + modifier = Modifier.size(15.dp) + ) + } + if (hasEncryption && messageIndicatorsConfig.contains("encryption_indicator")) { + Image( + imageVector = Icons.Default.Lock, + colorFilter = ColorFilter.tint(Color.Green), + contentDescription = null, + modifier = Modifier.size(15.dp) + ) + } + } + } + }.apply { + tag = messageInfoTag + addOnLayoutChangeListener { _, left, _, right, _, _, _, _, _ -> + layout(left, 0, right, 0) + } + layoutParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT + ) + parentLinearLayout.addView(this) + } + } + } + } +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ComposeIcons.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ComposeIcons.kt @@ -0,0 +1,77 @@ +package me.rhunk.snapenhance.core.ui + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.group +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + + +val AppleLogo: ImageVector + get() { + return ImageVector.Builder( + defaultWidth = 800.dp, + defaultHeight = 800.dp, + viewportWidth = 27f, + viewportHeight = 27f, + ).apply { + group { + path( + fill = SolidColor(Color(0xFF000000)), + fillAlpha = 1.0f, + stroke = null, + strokeAlpha = 1.0f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero + ) { + moveTo(15.769f, 0f) + curveToRelative(0.053f, 0f, 0.106f, 0f, 0.162f, 0f) + curveToRelative(0.13f, 1.606f, -0.483f, 2.806f, -1.228f, 3.675f) + curveToRelative(-0.731f, 0.863f, -1.732f, 1.7f, -3.351f, 1.573f) + curveToRelative(-0.108f, -1.583f, 0.506f, -2.694f, 1.25f, -3.561f) + curveTo(13.292f, 0.879f, 14.557f, 0.16f, 15.769f, 0f) + close() + } + path( + fill = SolidColor(Color(0xFF000000)), + fillAlpha = 1.0f, + stroke = null, + strokeAlpha = 1.0f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero + ) { + moveTo(20.67f, 16.716f) + curveToRelative(0f, 0.016f, 0f, 0.03f, 0f, 0.045f) + curveToRelative(-0.455f, 1.378f, -1.104f, 2.559f, -1.896f, 3.655f) + curveToRelative(-0.723f, 0.995f, -1.609f, 2.334f, -3.191f, 2.334f) + curveToRelative(-1.367f, 0f, -2.275f, -0.879f, -3.676f, -0.903f) + curveToRelative(-1.482f, -0.024f, -2.297f, 0.735f, -3.652f, 0.926f) + curveToRelative(-0.155f, 0f, -0.31f, 0f, -0.462f, 0f) + curveToRelative(-0.995f, -0.144f, -1.798f, -0.932f, -2.383f, -1.642f) + curveToRelative(-1.725f, -2.098f, -3.058f, -4.808f, -3.306f, -8.276f) + curveToRelative(0f, -0.34f, 0f, -0.679f, 0f, -1.019f) + curveToRelative(0.105f, -2.482f, 1.311f, -4.5f, 2.914f, -5.478f) + curveToRelative(0.846f, -0.52f, 2.009f, -0.963f, 3.304f, -0.765f) + curveToRelative(0.555f, 0.086f, 1.122f, 0.276f, 1.619f, 0.464f) + curveToRelative(0.471f, 0.181f, 1.06f, 0.502f, 1.618f, 0.485f) + curveToRelative(0.378f, -0.011f, 0.754f, -0.208f, 1.135f, -0.347f) + curveToRelative(1.116f, -0.403f, 2.21f, -0.865f, 3.652f, -0.648f) + curveToRelative(1.733f, 0.262f, 2.963f, 1.032f, 3.723f, 2.22f) + curveToRelative(-1.466f, 0.933f, -2.625f, 2.339f, -2.427f, 4.74f) + curveTo(17.818f, 14.688f, 19.086f, 15.964f, 20.67f, 16.716f) + close() + } + } + }.build() + } +