Skip to content

Commit

Permalink
feat(core): message indicators
Browse files Browse the repository at this point in the history
  • Loading branch information
rhunk committed Mar 16, 2024
1 parent 52addbe commit 3d6d070
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 47 deletions.
11 changes: 8 additions & 3 deletions common/src/main/assets/lang/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class FeatureManager(
DisableConfirmationDialogs(),
MixerStories(),
DisableComposerModules(),
FideliusIndicator(),
MessageIndicators(),
EditTextOverride(),
PreventForcedLogout(),
SuspendLocationUpdates(),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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)
}
}
}
}
}
77 changes: 77 additions & 0 deletions core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ComposeIcons.kt
Original file line number Diff line number Diff line change
@@ -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()
}

0 comments on commit 3d6d070

Please sign in to comment.