commit 94b519614d0e00af0623be239a7ba4d3e5708643
parent 0f3fb7bcd0d111c47e585b3d09ea92e86774acaf
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Wed, 17 Jan 2024 19:03:54 +0100

feat(scripting): better debug ui

Diffstat:
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/downloader/MediaDownloader.kt | 13++-----------
Acore/src/main/kotlin/me/rhunk/snapenhance/core/ui/DebugComponents.kt | 22++++++++++++++++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/ChatActionMenu.kt | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
3 files changed, 139 insertions(+), 68 deletions(-)

diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/downloader/MediaDownloader.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/downloader/MediaDownloader.kt @@ -4,10 +4,8 @@ import android.annotation.SuppressLint import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri -import android.text.InputType import android.view.Gravity import android.view.ViewGroup.MarginLayoutParams -import android.widget.EditText import android.widget.ImageView import android.widget.LinearLayout import android.widget.ProgressBar @@ -35,6 +33,7 @@ import me.rhunk.snapenhance.core.features.impl.downloader.decoder.MessageDecoder import me.rhunk.snapenhance.core.features.impl.messaging.Messaging import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper +import me.rhunk.snapenhance.core.ui.debugEditText import me.rhunk.snapenhance.core.util.hook.HookAdapter import me.rhunk.snapenhance.core.util.hook.HookStage import me.rhunk.snapenhance.core.util.hook.hook @@ -159,15 +158,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp ViewAppearanceHelper.newAlertDialogBuilder(context.mainActivity!!).apply { setTitle("Debug Media Info") - setView(EditText(context).apply { - inputType = InputType.TYPE_NULL - setTextIsSelectable(true) - isSingleLine = false - textSize = 12f - setPadding(20, 20, 20, 20) - setText(mediaInfoText) - setTextColor(context.resources.getColor(android.R.color.white, context.theme)) - }) + setView(debugEditText(context, mediaInfoText)) setNeutralButton("Copy") { _, _ -> this@MediaDownloader.context.copyToClipboard(mediaInfoText) } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/DebugComponents.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/DebugComponents.kt @@ -0,0 +1,21 @@ +package me.rhunk.snapenhance.core.ui + +import android.content.Context +import android.text.InputType +import android.view.View +import android.widget.EditText +import android.widget.ScrollView + +fun debugEditText(context: Context, initialText: String): View { + return ScrollView(context).apply { + isSmoothScrollingEnabled = true + addView(EditText(context).apply { + inputType = InputType.TYPE_NULL + isSingleLine = false + setTextIsSelectable(true) + textSize = 12f + setPadding(20, 20, 20, 20) + setText(initialText) + }) + } +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/ChatActionMenu.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/impl/ChatActionMenu.kt @@ -7,22 +7,34 @@ import android.view.ViewGroup import android.view.ViewGroup.MarginLayoutParams import android.widget.Button import android.widget.LinearLayout -import android.widget.TextView +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import me.rhunk.snapenhance.common.data.ContentType +import me.rhunk.snapenhance.common.ui.createComposeView import me.rhunk.snapenhance.common.util.protobuf.ProtoReader import me.rhunk.snapenhance.core.features.impl.downloader.MediaDownloader +import me.rhunk.snapenhance.core.features.impl.downloader.decoder.MessageDecoder import me.rhunk.snapenhance.core.features.impl.experiments.ConvertMessageLocally import me.rhunk.snapenhance.core.features.impl.messaging.Messaging import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper import me.rhunk.snapenhance.core.ui.ViewTagState import me.rhunk.snapenhance.core.ui.applyTheme +import me.rhunk.snapenhance.core.ui.debugEditText import me.rhunk.snapenhance.core.ui.menu.AbstractMenu import me.rhunk.snapenhance.core.ui.triggerCloseTouchEvent import me.rhunk.snapenhance.core.util.hook.HookStage import me.rhunk.snapenhance.core.util.hook.hook import me.rhunk.snapenhance.core.util.ktx.getDimens -import java.time.Instant +import java.text.SimpleDateFormat +import java.util.Date @SuppressLint("DiscouragedApi") @@ -50,15 +62,17 @@ class ChatActionMenu : AbstractMenu() { } } - private fun copyAlertDialog(context: Context, title: String, text: String) { - ViewAppearanceHelper.newAlertDialogBuilder(context).apply { - setTitle(title) - setMessage(text) - setPositiveButton("OK") { dialog, _ -> dialog.dismiss() } - setNegativeButton("Copy") { _, _ -> - this@ChatActionMenu.context.copyToClipboard(text, title) - } - }.show() + private fun debugAlertDialog(context: Context, title: String, text: String) { + this@ChatActionMenu.context.runOnUiThread { + ViewAppearanceHelper.newAlertDialogBuilder(context).apply { + setTitle(title) + setView(debugEditText(context, text)) + setPositiveButton("OK") { dialog, _ -> dialog.dismiss() } + setNegativeButton("Copy") { _, _ -> + this@ChatActionMenu.context.copyToClipboard(text, title) + } + }.show() + } } private val lastFocusedMessage @@ -78,6 +92,7 @@ class ChatActionMenu : AbstractMenu() { } } + @OptIn(ExperimentalLayoutApi::class) @SuppressLint("SetTextI18n", "DiscouragedApi", "ClickableViewAccessibility") override fun inject(parent: ViewGroup, view: View, viewConsumer: (View) -> Unit) { val viewGroup = parent.parent.parent as? ViewGroup ?: return @@ -176,56 +191,99 @@ class ChatActionMenu : AbstractMenu() { } if (context.isDeveloper) { - viewGroup.addView(createContainer(viewGroup).apply { - val debugText = StringBuilder() - - setOnClickListener { - this@ChatActionMenu.context.copyToClipboard(debugText.toString(), "debug") - } - - addView(TextView(viewGroup.context).apply { - setPadding(20, 20, 20, 20) - textSize = 10f - addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> - val arroyoMessage = lastFocusedMessage ?: return@addOnLayoutChangeListener - text = debugText.apply { - runCatching { - clear() - append("sender_id: ${arroyoMessage.senderId}\n") - append("client_id: ${arroyoMessage.clientMessageId}, server_id: ${arroyoMessage.serverMessageId}\n") - append("conversation_id: ${arroyoMessage.clientConversationId}\n") - append("arroyo_content_type: ${ContentType.fromId(arroyoMessage.contentType)} (${arroyoMessage.contentType})\n") - append("parsed_content_type: ${ - ContentType.fromMessageContainer( - ProtoReader(arroyoMessage.messageContent!!).followPath(4, 4) - ).let { "$it (${it?.id})" }}\n") - append("creation_timestamp: ${arroyoMessage.creationTimestamp} (${Instant.ofEpochMilli(arroyoMessage.creationTimestamp)})\n") - append("read_timestamp: ${arroyoMessage.readTimestamp} (${Instant.ofEpochMilli(arroyoMessage.readTimestamp)})\n") - append("is_messagelogger_deleted: ${messageLogger.isMessageDeleted(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong())}\n") - append("is_messagelogger_stored: ${messageLogger.getMessageObject(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong()) != null}\n") - }.onFailure { - debugText.append("Error: $it\n") - } - }.toString().trimEnd() + val composeDebugView = createComposeView(viewGroup.context) { + FlowRow( + modifier = Modifier.fillMaxWidth().padding(5.dp), + horizontalArrangement = Arrangement.spacedBy(3.dp) + ) { + Button(onClick = { + val arroyoMessage = lastFocusedMessage ?: return@Button + debugAlertDialog(viewGroup.context, + "Message Info", + StringBuilder().apply { + runCatching { + append("conversation_id: ${arroyoMessage.clientConversationId}\n") + append("sender_id: ${arroyoMessage.senderId}\n") + append("client_id: ${arroyoMessage.clientMessageId}, server_id: ${arroyoMessage.serverMessageId}\n") + append("content_type: ${ContentType.fromId(arroyoMessage.contentType)} (${arroyoMessage.contentType})\n") + append("parsed_content_type: ${ + ContentType.fromMessageContainer( + ProtoReader(arroyoMessage.messageContent!!).followPath(4, 4) + ).let { "$it (${it?.id})" }}\n") + append("creation_timestamp: ${ + SimpleDateFormat.getDateTimeInstance().format( + Date(arroyoMessage.creationTimestamp) + )} (${arroyoMessage.creationTimestamp})\n") + append("read_timestamp: ${SimpleDateFormat.getDateTimeInstance().format( + Date(arroyoMessage.readTimestamp) + )} (${arroyoMessage.readTimestamp})\n") + append("ml_deleted: ${messageLogger.isMessageDeleted(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong())}, ") + append("ml_stored: ${messageLogger.getMessageObject(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong()) != null}\n") + } + }.toString() + ) + }) { + Text("Info") } - }) + Button(onClick = { + val arroyoMessage = lastFocusedMessage ?: return@Button + messaging.conversationManager?.fetchMessage(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong(), onSuccess = { message -> + val decodedAttachments = MessageDecoder.decode(message.messageContent!!) - // action buttons - addView(LinearLayout(viewGroup.context).apply { - orientation = LinearLayout.HORIZONTAL - addView(Button(viewGroup.context).apply { - text = "Show Deleted Message Object" - setOnClickListener { - val message = lastFocusedMessage ?: return@setOnClickListener - copyAlertDialog( + debugAlertDialog( viewGroup.context, - "Deleted Message Object", - messageLogger.getMessageObject(message.clientConversationId!!, message.clientMessageId.toLong())?.toString() - ?: "null" + "Media References", + decodedAttachments.mapIndexed { index, attachment -> + StringBuilder().apply { + append("---- media $index ----\n") + append("resolveProto: ${attachment.mediaUrlKey}\n") + append("type: ${attachment.type}\n") + attachment.attachmentInfo?.apply { + encryption?.let { + append("encryption:\n - key: ${it.key}\n - iv: ${it.iv}\n") + } + resolution?.let { + append("resolution: ${it.first}x${it.second}\n") + } + duration?.let { + append("duration: $it\n") + } + } + }.toString() + }.joinToString("\n\n") ) - } - }) - }) + }) + }) { + Text("Refs") + } + Button(onClick = { + val message = lastFocusedMessage ?: return@Button + debugAlertDialog( + viewGroup.context, + "Arroyo proto", + message.messageContent?.let { ProtoReader(it) }?.toString() ?: "empty" + ) + }) { + Text("Arroyo proto") + } + Button(onClick = { + val arroyoMessage = lastFocusedMessage ?: return@Button + messaging.conversationManager?.fetchMessage(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong(), onSuccess = { message -> + debugAlertDialog( + viewGroup.context, + "Message proto", + message.messageContent?.content?.let { ProtoReader(it) }?.toString() ?: "empty" + ) + }, onError = { + this@ChatActionMenu.context.shortToast("Failed to fetch message: $it") + }) + }) { + Text("Message proto") + } + } + } + viewGroup.addView(createContainer(viewGroup).apply { + addView(composeDebugView) }) }