Merge pull request #139 from schrodingerspet/fix/message-logger-import-persistence
fix(ui): enforce Hide Friend Feed Entry on main friend feed
This commit is contained in:
@@ -1,17 +1,26 @@
|
||||
package me.eternal.purrfectsnap.core.features.impl.ui
|
||||
|
||||
import android.view.View
|
||||
import me.eternal.purrfectsnap.common.data.MessagingRuleType
|
||||
import me.eternal.purrfectsnap.common.data.RuleState
|
||||
|
||||
import me.eternal.purrfectsnap.core.event.events.impl.BindViewEvent
|
||||
import me.eternal.purrfectsnap.core.features.MessagingRuleFeature
|
||||
import me.eternal.purrfectsnap.core.ui.hideViewCompletely
|
||||
import me.eternal.purrfectsnap.core.util.dataBuilder
|
||||
import me.eternal.purrfectsnap.core.util.hook.HookStage
|
||||
import me.eternal.purrfectsnap.core.util.hook.hook
|
||||
import me.eternal.purrfectsnap.core.util.ktx.getObjectField
|
||||
import me.eternal.purrfectsnap.core.wrapper.impl.SnapUUID
|
||||
import me.eternal.purrfectsnap.mapper.impl.CallbackMapper
|
||||
import java.util.ArrayList
|
||||
|
||||
class HideFriendFeedEntry : MessagingRuleFeature("HideFriendFeedEntry", ruleType = MessagingRuleType.HIDE_FRIEND_FEED) {
|
||||
@Volatile
|
||||
private var cachedRuleIds: Set<String> = emptySet()
|
||||
|
||||
@Volatile
|
||||
private var cachedRuleIdsAt = 0L
|
||||
|
||||
private fun createDeletedFeedEntry(conversationIdInstance: Any) = findClass("com.snapchat.client.messaging.DeletedFeedEntry").dataBuilder {
|
||||
from("mFeedEntryIdentifier") {
|
||||
set("mConversationId", conversationIdInstance)
|
||||
@@ -19,10 +28,47 @@ class HideFriendFeedEntry : MessagingRuleFeature("HideFriendFeedEntry", ruleType
|
||||
set("mReason", "CLEAR_CONVERSATION")
|
||||
}
|
||||
|
||||
private fun filterFriendFeed(entries: ArrayList<Any>, deletedEntries: ArrayList<Any>? = null) {
|
||||
private fun getRuleIdsSnapshot(): Set<String> {
|
||||
val now = System.currentTimeMillis()
|
||||
if (now - cachedRuleIdsAt <= 1_000L) return cachedRuleIds
|
||||
|
||||
return context.bridgeClient.getRuleIds(ruleType).toSet().also {
|
||||
cachedRuleIds = it
|
||||
cachedRuleIdsAt = now
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveRuleTargets(conversationId: String): Set<String> {
|
||||
val targets = linkedSetOf(conversationId)
|
||||
context.database.getDMOtherParticipant(conversationId)?.let { targets.add(it) }
|
||||
context.database.getFeedEntryByConversationId(conversationId)?.let { entry ->
|
||||
entry.friendUserId?.let { targets.add(it) }
|
||||
entry.participants?.forEach { targets.add(it) }
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
private fun shouldHideConversation(
|
||||
conversationId: String,
|
||||
ruleIds: Set<String>,
|
||||
ruleState: RuleState?
|
||||
): Boolean {
|
||||
if (ruleState == null) return false
|
||||
val isExplicitRuleMatch = resolveRuleTargets(conversationId).any { it in ruleIds }
|
||||
return if (ruleState == RuleState.BLACKLIST) !isExplicitRuleMatch else isExplicitRuleMatch
|
||||
}
|
||||
|
||||
private fun filterFriendFeed(
|
||||
entries: ArrayList<Any>,
|
||||
ruleIds: Set<String>,
|
||||
ruleState: RuleState?,
|
||||
deletedEntries: ArrayList<Any>? = null
|
||||
) {
|
||||
if (ruleState == null || entries.isEmpty()) return
|
||||
entries.removeIf { feedEntry ->
|
||||
val conversationIdInstance = feedEntry.getObjectField("mConversationId") ?: return@removeIf false
|
||||
if (canUseRule(SnapUUID(conversationIdInstance).toString())) {
|
||||
val conversationId = SnapUUID(conversationIdInstance).toString()
|
||||
if (shouldHideConversation(conversationId, ruleIds, ruleState)) {
|
||||
deletedEntries?.add(createDeletedFeedEntry(conversationIdInstance)!!)
|
||||
true
|
||||
} else {
|
||||
@@ -31,6 +77,12 @@ class HideFriendFeedEntry : MessagingRuleFeature("HideFriendFeedEntry", ruleType
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideBoundChatFeedRow(view: View) {
|
||||
view.hideViewCompletely()
|
||||
(view.parent as? View)?.hideViewCompletely()
|
||||
(view.parent?.parent as? View)?.hideViewCompletely()
|
||||
}
|
||||
|
||||
private fun hookCallbackMethod(
|
||||
hookedCallbacks: MutableSet<String>,
|
||||
callbackClassName: String,
|
||||
@@ -51,6 +103,14 @@ class HideFriendFeedEntry : MessagingRuleFeature("HideFriendFeedEntry", ruleType
|
||||
override fun init() {
|
||||
if (!context.config.userInterface.hideFriendFeedEntry.get()) return
|
||||
|
||||
context.event.subscribe(BindViewEvent::class) { event ->
|
||||
event.friendFeedItem { conversationId ->
|
||||
if (shouldHideConversation(conversationId, getRuleIdsSnapshot(), getRuleState())) {
|
||||
hideBoundChatFeedRow(event.view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.mappings.useMapper(CallbackMapper::class) {
|
||||
classLoader = context.androidContext.classLoader
|
||||
val hasFetchAndSyncCallback = callbacks.getAsMap()?.entries?.any {
|
||||
@@ -69,13 +129,13 @@ class HideFriendFeedEntry : MessagingRuleFeature("HideFriendFeedEntry", ruleType
|
||||
when {
|
||||
callbackName.startsWith("FetchAndSyncFeed") && callbackName.endsWith("Callback") -> {
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onFetchAndSyncFeedComplete") { param ->
|
||||
val deletedConversations: ArrayList<Any> = param.arg(2)
|
||||
filterFriendFeed(param.arg(0), deletedConversations)
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
val deletedConversations = param.argNullable<ArrayList<Any>>(2)
|
||||
val ruleIds = getRuleIdsSnapshot()
|
||||
val ruleState = getRuleState()
|
||||
filterFriendFeed(entries, ruleIds, ruleState, deletedConversations)
|
||||
|
||||
if (deletedConversations.any {
|
||||
val uuid = SnapUUID(it.getObjectField("mFeedEntryIdentifier")?.getObjectField("mConversationId")).toString()
|
||||
context.database.getFeedEntryByConversationId(uuid) != null
|
||||
}) {
|
||||
if (deletedConversations?.isNotEmpty() == true) {
|
||||
param.setArg(4, true)
|
||||
}
|
||||
}
|
||||
@@ -83,34 +143,40 @@ class HideFriendFeedEntry : MessagingRuleFeature("HideFriendFeedEntry", ruleType
|
||||
|
||||
callbackName.contains("SyncFeed") && callbackName.endsWith("Callback") -> {
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onSyncFeedComplete") { param ->
|
||||
filterFriendFeed(param.arg(0), param.argNullable(2))
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
filterFriendFeed(entries, getRuleIdsSnapshot(), getRuleState(), param.argNullable(2))
|
||||
}
|
||||
}
|
||||
|
||||
callbackName == "FetchFeedCallback" || callbackName.contains("FetchFeedCallback") -> {
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onFetchFeedComplete") { param ->
|
||||
filterFriendFeed(param.arg(0))
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
filterFriendFeed(entries, getRuleIdsSnapshot(), getRuleState())
|
||||
}
|
||||
}
|
||||
|
||||
callbackName == "FetchFeedEntriesCallback" || callbackName.contains("FetchFeedEntriesCallback") -> {
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onFetchFeedEntriesComplete") { param ->
|
||||
filterFriendFeed(param.arg(0))
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
filterFriendFeed(entries, getRuleIdsSnapshot(), getRuleState())
|
||||
}
|
||||
}
|
||||
|
||||
callbackName == "QueryFeedCallback" || callbackName.contains("QueryFeedCallback") -> {
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onQueryFeedComplete") { param ->
|
||||
filterFriendFeed(param.arg(0))
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
filterFriendFeed(entries, getRuleIdsSnapshot(), getRuleState())
|
||||
}
|
||||
}
|
||||
|
||||
callbackName == "FeedManagerDelegate" -> {
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onFeedEntriesUpdated") { param ->
|
||||
filterFriendFeed(param.arg(0))
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
filterFriendFeed(entries, getRuleIdsSnapshot(), getRuleState())
|
||||
}
|
||||
hookCallbackMethod(hookedCallbacks, callbackClassName ?: return@forEach, "onInternalSyncFeed") { param ->
|
||||
filterFriendFeed(param.arg(0))
|
||||
val entries = param.argNullable<ArrayList<Any>>(0) ?: return@hookCallbackMethod
|
||||
filterFriendFeed(entries, getRuleIdsSnapshot(), getRuleState())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user