diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json index 7bef6356..a4b1b22c 100644 --- a/common/src/main/assets/lang/en_US.json +++ b/common/src/main/assets/lang/en_US.json @@ -558,6 +558,10 @@ "name": "Call Start Confirmation", "description": "Shows a confirmation dialog when starting a call" }, + "unlimited_conversation_pinning": { + "name": "Unlimited Conversation Pinning", + "description": "Allows you to pin an unlimited amount of conversations locally" + }, "prevent_message_sending": { "name": "Prevent Message Sending", "description": "Prevents sending certain types of messages" diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt index a4f338f2..4c10b2b4 100644 --- a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt +++ b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt @@ -61,6 +61,7 @@ class MessagingTweaks : ConfigContainer() { val halfSwipeNotifier = container("half_swipe_notifier", HalfSwipeNotifierConfig()) { requireRestart()} val messagePreviewLength = integer("message_preview_length", defaultValue = 20) val callStartConfirmation = boolean("call_start_confirmation") { requireRestart() } + val unlimitedConversationPinning = boolean("unlimited_conversation_pinning") { requireRestart() } val autoSaveMessagesInConversations = multiple("auto_save_messages_in_conversations", "CHAT", "SNAP", diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/PinConversations.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/PinConversations.kt index 1a5af61b..b583a4be 100644 --- a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/PinConversations.kt +++ b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/ui/PinConversations.kt @@ -5,6 +5,7 @@ import me.rhunk.snapenhance.common.data.RuleState import me.rhunk.snapenhance.core.features.FeatureLoadParams import me.rhunk.snapenhance.core.features.MessagingRuleFeature import me.rhunk.snapenhance.core.util.hook.HookStage +import me.rhunk.snapenhance.core.util.hook.Hooker import me.rhunk.snapenhance.core.util.hook.hook import me.rhunk.snapenhance.core.util.hook.hookConstructor import me.rhunk.snapenhance.core.util.ktx.getObjectField @@ -13,10 +14,22 @@ import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID class PinConversations : MessagingRuleFeature("PinConversations", MessagingRuleType.PIN_CONVERSATION, loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) { override fun onActivityCreate() { + if (!context.config.messaging.unlimitedConversationPinning.get()) return + context.classCache.feedManager.hook("setPinnedConversationStatus", HookStage.BEFORE) { param -> val conversationUUID = SnapUUID(param.arg(0)) val isPinned = param.arg(1).toString() == "PINNED" setState(conversationUUID.toString(), isPinned) + val callback = param.arg(2) + mutableSetOf<() -> Unit>().apply { + addAll(Hooker.ephemeralHookObjectMethod(callback::class.java, callback,"onSuccess", HookStage.BEFORE) { + forEach { it() } + }) + addAll(Hooker.ephemeralHookObjectMethod(callback::class.java, callback,"onError", HookStage.BEFORE) { methodParam -> + methodParam.setResult(null) + callback::class.java.getDeclaredMethod("onSuccess").invoke(callback) + }) + } } context.classCache.conversation.hookConstructor(HookStage.AFTER) { param -> diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/util/hook/Hooker.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/util/hook/Hooker.kt index 3999afa5..a150681b 100644 --- a/core/src/main/kotlin/me/rhunk/snapenhance/core/util/hook/Hooker.kt +++ b/core/src/main/kotlin/me/rhunk/snapenhance/core/util/hook/Hooker.kt @@ -109,13 +109,16 @@ object Hooker { methodName: String, stage: HookStage, crossinline hookConsumer: (HookAdapter) -> Unit - ) { - val unhooks: MutableSet = HashSet() + ): Set<() -> Unit> { + val unhooks = mutableSetOf() hook(clazz, methodName, stage) { param-> if (param.nullableThisObject() != instance) return@hook unhooks.forEach { it.unhook() } hookConsumer(param) }.also { unhooks.addAll(it) } + return unhooks.map { + { it.unhook() } + }.toSet() } inline fun ephemeralHookConstructor(