commit 93490c323c7f39a0945f3aa1b325c0c76d484292
parent 8c71e4af27c7b08e1a8c0901b5efaa5bba4cb3a2
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Wed, 17 Jan 2024 14:53:15 +0100
feat: stealth mode indicator
Diffstat:
5 files changed, 90 insertions(+), 0 deletions(-)
diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json
@@ -340,6 +340,10 @@
"name": "Fidelius Indicator",
"description": "Adds a green circle next to messages that have been sent only to you"
},
+ "stealth_mode_indicator": {
+ "name": "Stealth Mode Indicator",
+ "description": "Adds a \uD83D\uDC7B emoji next to conversations in stealth mode"
+ },
"edit_text_override": {
"name": "Edit Text Override",
"description": "Overrides text field behavior"
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
@@ -49,6 +49,7 @@ class UserInterfaceTweaks : ConfigContainer() {
val hideSettingsGear = boolean("hide_settings_gear") { requireRestart() }
val verticalStoryViewer = boolean("vertical_story_viewer") { requireRestart() }
val fideliusIndicator = boolean("fidelius_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/MessagingRuleFeature.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/MessagingRuleFeature.kt
@@ -4,6 +4,11 @@ import me.rhunk.snapenhance.common.data.MessagingRuleType
import me.rhunk.snapenhance.common.data.RuleState
abstract class MessagingRuleFeature(name: String, val ruleType: MessagingRuleType, loadParams: Int = 0) : Feature(name, loadParams) {
+ private val listeners = mutableListOf<(String, Boolean) -> Unit>()
+
+ fun addStateListener(listener: (conversationId: String, newState: Boolean) -> Unit) {
+ listeners.add(listener)
+ }
open fun getRuleState() = context.config.rules.getRuleState(ruleType)
@@ -13,6 +18,7 @@ abstract class MessagingRuleFeature(name: String, val ruleType: MessagingRuleTyp
ruleType,
state
)
+ listeners.forEach { it(conversationId, state) }
}
fun getState(conversationId: String) =
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/StealthModeIndicator.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/StealthModeIndicator.kt
@@ -0,0 +1,77 @@
+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 kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+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.features.impl.spying.StealthMode
+import me.rhunk.snapenhance.core.ui.addForegroundDrawable
+import me.rhunk.snapenhance.core.ui.removeForegroundDrawable
+import me.rhunk.snapenhance.core.util.EvictingMap
+import me.rhunk.snapenhance.core.util.ktx.getDimens
+import me.rhunk.snapenhance.core.util.ktx.getIdentifier
+
+class StealthModeIndicator : Feature("StealthModeIndicator", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
+ private val stealthMode by lazy { context.feature(StealthMode::class) }
+ private val listeners = EvictingMap<String, (Boolean) -> Unit>(100)
+
+ private fun fetchStealthState(conversationId: String, result: (Boolean) -> Unit) {
+ context.coroutineScope.launch {
+ val isStealth = stealthMode.getState(conversationId)
+ withContext(Dispatchers.Main) {
+ result(isStealth)
+ }
+ }
+ }
+
+ override fun onActivityCreate() {
+ if (!context.config.userInterface.stealthModeIndicator.get()) return
+
+ val secondaryTextSize = context.resources.getDimens("ff_feed_cell_secondary_text_size").toFloat()
+ val sigColorTextPrimary = context.mainActivity!!.obtainStyledAttributes(
+ intArrayOf(context.resources.getIdentifier("sigColorTextPrimary", "attr"))
+ ).use { it.getColor(0, 0) }
+
+ stealthMode.addStateListener { conversationId, state ->
+ runCatching {
+ listeners[conversationId]?.invoke(state)
+ }.onFailure {
+ context.log.error("Failed to update stealth mode indicator", it)
+ }
+ }
+
+ context.event.subscribe(BindViewEvent::class) { event ->
+ fun updateStealthIndicator(isStealth: Boolean = true) {
+ event.view.removeForegroundDrawable("stealthModeIndicator")
+ if (!isStealth || !event.view.isAttachedToWindow) return
+ event.view.addForegroundDrawable("stealthModeIndicator", ShapeDrawable(object : Shape() {
+ override fun draw(canvas: Canvas, paint: Paint) {
+ paint.textSize = secondaryTextSize
+ paint.color = sigColorTextPrimary
+ canvas.drawText(
+ "\uD83D\uDC7B",
+ 0f,
+ canvas.height.toFloat() - secondaryTextSize / 2,
+ paint
+ )
+ }
+ }))
+ }
+
+ event.friendFeedItem { conversationId ->
+ listeners[conversationId] = addStateListener@{ stealth ->
+ updateStealthIndicator(stealth)
+ }
+ fetchStealthState(conversationId) { isStealth ->
+ updateStealthIndicator(isStealth)
+ }
+ }
+ }
+ }
+}+
\ No newline at end of file
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/manager/impl/FeatureManager.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/manager/impl/FeatureManager.kt
@@ -116,6 +116,7 @@ class FeatureManager(
ConversationToolbox(),
SpotlightCommentsUsername(),
OperaViewerParamsOverride(),
+ StealthModeIndicator(),
)
initializeFeatures()