mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 21:10:20 +02:00
feat(scripting): better debug ui
This commit is contained in:
parent
0f3fb7bcd0
commit
94b519614d
@ -4,10 +4,8 @@ import android.annotation.SuppressLint
|
|||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.InputType
|
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.ProgressBar
|
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.messaging.Messaging
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
||||||
import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper
|
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.HookAdapter
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
@ -159,15 +158,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
|||||||
|
|
||||||
ViewAppearanceHelper.newAlertDialogBuilder(context.mainActivity!!).apply {
|
ViewAppearanceHelper.newAlertDialogBuilder(context.mainActivity!!).apply {
|
||||||
setTitle("Debug Media Info")
|
setTitle("Debug Media Info")
|
||||||
setView(EditText(context).apply {
|
setView(debugEditText(context, mediaInfoText))
|
||||||
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))
|
|
||||||
})
|
|
||||||
setNeutralButton("Copy") { _, _ ->
|
setNeutralButton("Copy") { _, _ ->
|
||||||
this@MediaDownloader.context.copyToClipboard(mediaInfoText)
|
this@MediaDownloader.context.copyToClipboard(mediaInfoText)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -7,22 +7,34 @@ import android.view.ViewGroup
|
|||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.LinearLayout
|
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.data.ContentType
|
||||||
|
import me.rhunk.snapenhance.common.ui.createComposeView
|
||||||
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
|
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.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.experiments.ConvertMessageLocally
|
||||||
import me.rhunk.snapenhance.core.features.impl.messaging.Messaging
|
import me.rhunk.snapenhance.core.features.impl.messaging.Messaging
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
||||||
import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper
|
import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper
|
||||||
import me.rhunk.snapenhance.core.ui.ViewTagState
|
import me.rhunk.snapenhance.core.ui.ViewTagState
|
||||||
import me.rhunk.snapenhance.core.ui.applyTheme
|
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.menu.AbstractMenu
|
||||||
import me.rhunk.snapenhance.core.ui.triggerCloseTouchEvent
|
import me.rhunk.snapenhance.core.ui.triggerCloseTouchEvent
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
import me.rhunk.snapenhance.core.util.ktx.getDimens
|
import me.rhunk.snapenhance.core.util.ktx.getDimens
|
||||||
import java.time.Instant
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("DiscouragedApi")
|
@SuppressLint("DiscouragedApi")
|
||||||
@ -50,15 +62,17 @@ class ChatActionMenu : AbstractMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyAlertDialog(context: Context, title: String, text: String) {
|
private fun debugAlertDialog(context: Context, title: String, text: String) {
|
||||||
ViewAppearanceHelper.newAlertDialogBuilder(context).apply {
|
this@ChatActionMenu.context.runOnUiThread {
|
||||||
setTitle(title)
|
ViewAppearanceHelper.newAlertDialogBuilder(context).apply {
|
||||||
setMessage(text)
|
setTitle(title)
|
||||||
setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
|
setView(debugEditText(context, text))
|
||||||
setNegativeButton("Copy") { _, _ ->
|
setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
|
||||||
this@ChatActionMenu.context.copyToClipboard(text, title)
|
setNegativeButton("Copy") { _, _ ->
|
||||||
}
|
this@ChatActionMenu.context.copyToClipboard(text, title)
|
||||||
}.show()
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lastFocusedMessage
|
private val lastFocusedMessage
|
||||||
@ -78,6 +92,7 @@ class ChatActionMenu : AbstractMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@SuppressLint("SetTextI18n", "DiscouragedApi", "ClickableViewAccessibility")
|
@SuppressLint("SetTextI18n", "DiscouragedApi", "ClickableViewAccessibility")
|
||||||
override fun inject(parent: ViewGroup, view: View, viewConsumer: (View) -> Unit) {
|
override fun inject(parent: ViewGroup, view: View, viewConsumer: (View) -> Unit) {
|
||||||
val viewGroup = parent.parent.parent as? ViewGroup ?: return
|
val viewGroup = parent.parent.parent as? ViewGroup ?: return
|
||||||
@ -176,56 +191,99 @@ class ChatActionMenu : AbstractMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.isDeveloper) {
|
if (context.isDeveloper) {
|
||||||
viewGroup.addView(createContainer(viewGroup).apply {
|
val composeDebugView = createComposeView(viewGroup.context) {
|
||||||
val debugText = StringBuilder()
|
FlowRow(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(5.dp),
|
||||||
setOnClickListener {
|
horizontalArrangement = Arrangement.spacedBy(3.dp)
|
||||||
this@ChatActionMenu.context.copyToClipboard(debugText.toString(), "debug")
|
) {
|
||||||
}
|
Button(onClick = {
|
||||||
|
val arroyoMessage = lastFocusedMessage ?: return@Button
|
||||||
addView(TextView(viewGroup.context).apply {
|
debugAlertDialog(viewGroup.context,
|
||||||
setPadding(20, 20, 20, 20)
|
"Message Info",
|
||||||
textSize = 10f
|
StringBuilder().apply {
|
||||||
addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
runCatching {
|
||||||
val arroyoMessage = lastFocusedMessage ?: return@addOnLayoutChangeListener
|
append("conversation_id: ${arroyoMessage.clientConversationId}\n")
|
||||||
text = debugText.apply {
|
append("sender_id: ${arroyoMessage.senderId}\n")
|
||||||
runCatching {
|
append("client_id: ${arroyoMessage.clientMessageId}, server_id: ${arroyoMessage.serverMessageId}\n")
|
||||||
clear()
|
append("content_type: ${ContentType.fromId(arroyoMessage.contentType)} (${arroyoMessage.contentType})\n")
|
||||||
append("sender_id: ${arroyoMessage.senderId}\n")
|
append("parsed_content_type: ${
|
||||||
append("client_id: ${arroyoMessage.clientMessageId}, server_id: ${arroyoMessage.serverMessageId}\n")
|
ContentType.fromMessageContainer(
|
||||||
append("conversation_id: ${arroyoMessage.clientConversationId}\n")
|
ProtoReader(arroyoMessage.messageContent!!).followPath(4, 4)
|
||||||
append("arroyo_content_type: ${ContentType.fromId(arroyoMessage.contentType)} (${arroyoMessage.contentType})\n")
|
).let { "$it (${it?.id})" }}\n")
|
||||||
append("parsed_content_type: ${
|
append("creation_timestamp: ${
|
||||||
ContentType.fromMessageContainer(
|
SimpleDateFormat.getDateTimeInstance().format(
|
||||||
ProtoReader(arroyoMessage.messageContent!!).followPath(4, 4)
|
Date(arroyoMessage.creationTimestamp)
|
||||||
).let { "$it (${it?.id})" }}\n")
|
)} (${arroyoMessage.creationTimestamp})\n")
|
||||||
append("creation_timestamp: ${arroyoMessage.creationTimestamp} (${Instant.ofEpochMilli(arroyoMessage.creationTimestamp)})\n")
|
append("read_timestamp: ${SimpleDateFormat.getDateTimeInstance().format(
|
||||||
append("read_timestamp: ${arroyoMessage.readTimestamp} (${Instant.ofEpochMilli(arroyoMessage.readTimestamp)})\n")
|
Date(arroyoMessage.readTimestamp)
|
||||||
append("is_messagelogger_deleted: ${messageLogger.isMessageDeleted(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong())}\n")
|
)} (${arroyoMessage.readTimestamp})\n")
|
||||||
append("is_messagelogger_stored: ${messageLogger.getMessageObject(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong()) != null}\n")
|
append("ml_deleted: ${messageLogger.isMessageDeleted(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong())}, ")
|
||||||
}.onFailure {
|
append("ml_stored: ${messageLogger.getMessageObject(arroyoMessage.clientConversationId!!, arroyoMessage.clientMessageId.toLong()) != null}\n")
|
||||||
debugText.append("Error: $it\n")
|
}
|
||||||
}
|
}.toString()
|
||||||
}.toString().trimEnd()
|
)
|
||||||
|
}) {
|
||||||
|
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
|
debugAlertDialog(
|
||||||
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(
|
|
||||||
viewGroup.context,
|
viewGroup.context,
|
||||||
"Deleted Message Object",
|
"Media References",
|
||||||
messageLogger.getMessageObject(message.clientConversationId!!, message.clientMessageId.toLong())?.toString()
|
decodedAttachments.mapIndexed { index, attachment ->
|
||||||
?: "null"
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user