commit b378bdde871f28fb7408c2c99e01cf195f876937
parent 7aa05e996a3e0119c6c8cbfe41718551a5bde1ba
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Thu, 28 Dec 2023 00:42:01 +0100
feat(core): spotlight comments username
Diffstat:
6 files changed, 102 insertions(+), 0 deletions(-)
diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json
@@ -497,6 +497,10 @@
"name": "Block Ads",
"description": "Prevents Advertisements from being displayed"
},
+ "spotlight_comments_username": {
+ "name": "Spotlight Comments Username",
+ "description": "Shows author username in Spotlight comments"
+ },
"bypass_video_length_restriction": {
"name": "Bypass Video Length Restrictions",
"description": "Single: sends a single video\nSplit: split videos after editing"
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/Global.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/Global.kt
@@ -14,6 +14,7 @@ class Global : ConfigContainer() {
val disableMetrics = boolean("disable_metrics")
val disablePublicStories = boolean("disable_public_stories") { requireRestart(); requireCleanCache() }
val blockAds = boolean("block_ads")
+ val spotlightCommentsUsername = boolean("spotlight_comments_username") { requireRestart() }
val bypassVideoLengthRestriction = unique("bypass_video_length_restriction", "split", "single") { addNotices(
FeatureNotice.BAN_RISK); requireRestart(); nativeHooks() }
val disableGooglePlayDialogs = boolean("disable_google_play_dialogs") { requireRestart() }
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/messaging/Messaging.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/messaging/Messaging.kt
@@ -16,12 +16,16 @@ import me.rhunk.snapenhance.core.util.ktx.getObjectFieldOrNull
import me.rhunk.snapenhance.core.wrapper.impl.ConversationManager
import me.rhunk.snapenhance.core.wrapper.impl.Message
import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID
+import me.rhunk.snapenhance.core.wrapper.impl.Snapchatter
import me.rhunk.snapenhance.core.wrapper.impl.toSnapUUID
+import java.util.concurrent.Future
class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC or FeatureLoadParams.INIT_ASYNC or FeatureLoadParams.INIT_SYNC) {
var conversationManager: ConversationManager? = null
private set
private var conversationManagerDelegate: Any? = null
+ private var identityDelegate: Any? = null
+
var openedConversationUUID: SnapUUID? = null
private set
var lastFetchConversationUserUUID: SnapUUID? = null
@@ -57,6 +61,12 @@ class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_C
}
}
}
+
+ context.mappings.getMappedClass("callbacks", "IdentityDelegate").apply {
+ hookConstructor(HookStage.AFTER) {
+ identityDelegate = it.thisObject()
+ }
+ }
}
fun getFeedCachedMessageIds(conversationId: String) = feedCachedSnapMessages[conversationId]
@@ -169,4 +179,15 @@ class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_C
it.setResult(null)
}
}
+
+ fun fetchSnapchatterInfos(userIds: List<String>): List<Snapchatter> {
+ val identity = identityDelegate ?: return emptyList()
+ val future = identity::class.java.methods.first {
+ it.name == "fetchSnapchatterInfos"
+ }.invoke(identity, userIds.map {
+ it.toSnapUUID().instanceNonNull()
+ }) as Future<*>
+
+ return (future.get() as? List<*>)?.map { Snapchatter(it) } ?: return emptyList()
+ }
}
\ No newline at end of file
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/SpotlightCommentsUsername.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/SpotlightCommentsUsername.kt
@@ -0,0 +1,54 @@
+package me.rhunk.snapenhance.core.features.impl.ui
+
+import android.annotation.SuppressLint
+import android.widget.TextView
+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.messaging.Messaging
+import me.rhunk.snapenhance.core.util.EvictingMap
+import me.rhunk.snapenhance.core.util.ktx.getId
+
+class SpotlightCommentsUsername : Feature("SpotlightCommentsUsername", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
+ private val usernameCache = EvictingMap<String, String>(150)
+
+ @SuppressLint("SetTextI18n")
+ override fun onActivityCreate() {
+ if (!context.config.global.spotlightCommentsUsername.get()) return
+
+ val messaging = context.feature(Messaging::class)
+ val commentsCreatorBadgeTimestampId = context.resources.getId("comments_creator_badge_timestamp")
+
+ context.event.subscribe(BindViewEvent::class) { event ->
+ val commentsCreatorBadgeTimestamp = event.view.findViewById<TextView>(commentsCreatorBadgeTimestampId) ?: return@subscribe
+
+ val posterUserId = event.prevModel.toString().takeIf { it.startsWith("Comment") }
+ ?.substringAfter("posterUserId=")?.substringBefore(",")?.substringBefore(")") ?: return@subscribe
+
+ fun setUsername(username: String) {
+ usernameCache[posterUserId] = username
+ commentsCreatorBadgeTimestamp.text = " (${username})" + commentsCreatorBadgeTimestamp.text.toString()
+ }
+
+ usernameCache[posterUserId]?.let {
+ setUsername(it)
+ return@subscribe
+ }
+
+ context.coroutineScope.launch {
+ val username = runCatching {
+ messaging.fetchSnapchatterInfos(listOf(posterUserId)).firstOrNull()
+ }.onFailure {
+ context.log.error("Failed to fetch snapchatter info for user $posterUserId", it)
+ }.getOrNull()?.username ?: return@launch
+
+ withContext(Dispatchers.Main) {
+ setUsername(username)
+ }
+ }
+ }
+ }
+}+
\ 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
@@ -119,6 +119,7 @@ class FeatureManager(
PreventForcedLogout::class,
SuspendLocationUpdates::class,
ConversationToolbox::class,
+ SpotlightCommentsUsername::class,
)
initializeFeatures()
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/wrapper/impl/Snapchatter.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/wrapper/impl/Snapchatter.kt
@@ -0,0 +1,19 @@
+package me.rhunk.snapenhance.core.wrapper.impl
+
+import me.rhunk.snapenhance.core.wrapper.AbstractWrapper
+
+
+
+class BitmojiInfo(obj: Any?) : AbstractWrapper(obj) {
+ var avatarId by field<String?>("mAvatarId")
+ var backgroundId by field<String?>("mBackgroundId")
+ var sceneId by field<String?>("mSceneId")
+ var selfieId by field<String?>("mSelfieId")
+}
+
+class Snapchatter(obj: Any?) : AbstractWrapper(obj) {
+ val bitmojiInfo by field<BitmojiInfo?>("mBitmojiInfo")
+ var displayName by field<String?>("mDisplayName")
+ var userId by field("mUserId") { SnapUUID(it) }
+ var username by field<String>("mUsername")
+}+
\ No newline at end of file