commit 79be5da030dd2fa582ad3c7cb0bdd57181d072dc
parent bfe367efd0405408442f34f171497e3044e3220c
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun,  3 Dec 2023 12:42:57 +0100

feat: prevent message list auto scroll

Diffstat:
Mcommon/src/main/assets/lang/en_US.json | 4++++
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt | 1+
Acore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/tweaks/PreventMessageListAutoScroll.kt | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/manager/impl/FeatureManager.kt | 2++
4 files changed, 88 insertions(+), 0 deletions(-)

diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json @@ -259,6 +259,10 @@ "name": "Enhanced Friend Map Nametags", "description": "Improves the Nametags of friends on the Snapmap" }, + "prevent_message_list_auto_scroll": { + "name": "Prevent Message List Auto Scroll", + "description": "Prevents the message list from scrolling to the bottom when sending/receiving a message" + }, "streak_expiration_info": { "name": "Show Streak Expiration Info", "description": "Shows a Streak Expiration timer next to the Streaks counter" 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 @@ -29,6 +29,7 @@ class UserInterfaceTweaks : ConfigContainer() { val snapPreview = boolean("snap_preview") { addNotices(FeatureNotice.UNSTABLE); requireRestart() } val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) { requireRestart() } val mapFriendNameTags = boolean("map_friend_nametags") { requireRestart() } + val preventMessageListAutoScroll = boolean("prevent_message_list_auto_scroll") { requireRestart(); addNotices(FeatureNotice.UNSTABLE) } val streakExpirationInfo = boolean("streak_expiration_info") { requireRestart() } val hideFriendFeedEntry = boolean("hide_friend_feed_entry") { requireRestart() } val hideStreakRestore = boolean("hide_streak_restore") { requireRestart() } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/tweaks/PreventMessageListAutoScroll.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/tweaks/PreventMessageListAutoScroll.kt @@ -0,0 +1,80 @@ +package me.rhunk.snapenhance.core.features.impl.tweaks + +import android.view.View +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.util.hook.HookStage +import me.rhunk.snapenhance.core.util.hook.hook +import me.rhunk.snapenhance.core.wrapper.impl.Message +import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID + +class PreventMessageListAutoScroll : Feature("PreventMessageListAutoScroll", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) { + private var openedConversationId: String? = null + private val focusedMessages = mutableMapOf<View, Long>() + private var firstFocusedMessageId: Long? = null + private val delayedMessageUpdates = mutableListOf<() -> Unit>() + + override fun onActivityCreate() { + if (!context.config.userInterface.preventMessageListAutoScroll.get()) return + + context.mappings.getMappedClass("callbacks", "ConversationManagerDelegate").hook("onConversationUpdated", HookStage.BEFORE) { param -> + val updatedMessage = param.arg<ArrayList<*>>(2).map { Message(it) }.firstOrNull() ?: return@hook + if (openedConversationId != updatedMessage.messageDescriptor?.conversationId.toString()) return@hook + + // cancel if the message is already in focus + if (focusedMessages.entries.any { entry -> entry.value == updatedMessage.messageDescriptor?.messageId && entry.key.isAttachedToWindow }) return@hook + + val conversationLastMessages = context.database.getMessagesFromConversationId( + openedConversationId.toString(), + 4 + ) ?: return@hook + + if (conversationLastMessages.none { + focusedMessages.entries.any { entry -> entry.value == it.clientMessageId.toLong() && entry.key.isAttachedToWindow } + }) { + synchronized(delayedMessageUpdates) { + if (firstFocusedMessageId == null) firstFocusedMessageId = conversationLastMessages.lastOrNull()?.clientMessageId?.toLong() + delayedMessageUpdates.add { + param.invokeOriginal() + } + } + param.setResult(null) + } + } + + context.classCache.conversationManager.apply { + hook("enterConversation", HookStage.BEFORE) { param -> + openedConversationId = SnapUUID(param.arg(0)).toString() + } + hook("exitConversation", HookStage.BEFORE) { + openedConversationId = null + firstFocusedMessageId = null + synchronized(focusedMessages) { + focusedMessages.clear() + } + synchronized(delayedMessageUpdates) { + delayedMessageUpdates.clear() + } + } + } + + context.event.subscribe(BindViewEvent::class) { event -> + event.chatMessage { conversationId, messageId -> + if (conversationId != openedConversationId) return@chatMessage + synchronized(focusedMessages) { + focusedMessages[event.view] = messageId.toLong() + } + + if (delayedMessageUpdates.isNotEmpty() && focusedMessages.entries.any { entry -> entry.value == firstFocusedMessageId && entry.key.isAttachedToWindow }) { + delayedMessageUpdates.apply { + synchronized(this) { + removeIf { it(); true } + firstFocusedMessageId = null + } + } + } + } + } + } +}+ \ 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 @@ -20,6 +20,7 @@ import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger import me.rhunk.snapenhance.core.features.impl.spying.StealthMode import me.rhunk.snapenhance.core.features.impl.tweaks.BypassScreenshotDetection import me.rhunk.snapenhance.core.features.impl.tweaks.CameraTweaks +import me.rhunk.snapenhance.core.features.impl.tweaks.PreventMessageListAutoScroll import me.rhunk.snapenhance.core.features.impl.ui.* import me.rhunk.snapenhance.core.logger.CoreLogger import me.rhunk.snapenhance.core.manager.Manager @@ -111,6 +112,7 @@ class FeatureManager( Stories::class, DisableComposerModules::class, FideliusIndicator::class, + PreventMessageListAutoScroll::class, ) initializeFeatures()