From a53e5289e5545ef9c893dff717e581b48f543019 Mon Sep 17 00:00:00 2001 From: ACh Sulfate Date: Sun, 16 Jul 2023 22:50:37 +0800 Subject: [PATCH] fix: ShowMsgAt on NT --- app/src/main/java/me/ketal/hook/ShowMsgAt.kt | 78 ++++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/me/ketal/hook/ShowMsgAt.kt b/app/src/main/java/me/ketal/hook/ShowMsgAt.kt index ce292863e7..d5c790e393 100644 --- a/app/src/main/java/me/ketal/hook/ShowMsgAt.kt +++ b/app/src/main/java/me/ketal/hook/ShowMsgAt.kt @@ -22,6 +22,7 @@ package me.ketal.hook +import android.content.Context import android.text.Spannable import android.text.SpannableString import android.text.method.LinkMovementMethod @@ -29,18 +30,26 @@ import android.text.style.ClickableSpan import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.appcompat.app.AlertDialog import androidx.core.view.forEach import cc.ioctl.hook.profile.OpenProfileCard +import cc.ioctl.util.ui.FaultyDialog import com.tencent.qqnt.kernel.nativeinterface.MsgRecord +import com.tencent.qqnt.kernel.nativeinterface.TextElement import de.robv.android.xposed.XC_MethodHook import io.github.qauxv.base.annotation.UiItemAgentEntry +import io.github.qauxv.bridge.ntapi.ChatTypeConstants +import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi import io.github.qauxv.dsl.FunctionEntryRouter import io.github.qauxv.hook.CommonSwitchFunctionHook +import io.github.qauxv.ui.CommonContextWrapper import io.github.qauxv.util.Log +import io.github.qauxv.util.Toasts import io.github.qauxv.util.isTim import me.ketal.dispacher.BaseBubbleBuilderHook import me.ketal.dispacher.OnBubbleBuilder import me.singleneuron.data.MsgRecordData +import xyz.nextalone.util.SystemServiceUtils import xyz.nextalone.util.clazz import xyz.nextalone.util.findHostView import xyz.nextalone.util.get @@ -90,20 +99,77 @@ object ShowMsgAt : CommonSwitchFunctionHook(), OnBubbleBuilder { } } + @JvmStatic + public fun createUnknownUidDialog(outerContext: Context, uid: String) { + val ctx = CommonContextWrapper.createAppCompatContext(outerContext) + // BTN: OK, COPY + AlertDialog.Builder(ctx) + .setTitle("未知的 UID") + .setMessage(uid) + .setPositiveButton("确认") { _, _ -> } + .setNegativeButton("复制") { _, _ -> + SystemServiceUtils.copyToClipboard(ctx, uid) + Toasts.show(ctx, "已复制到剪贴板") + }.show() + } + + private fun createClickSpanForUid(uid: String?): ClickableSpan { + return object : ClickableSpan() { + override fun onClick(widget: View) { + val ctx = widget.context + if (uid?.startsWith("u_") == true) { + try { + val uin = RelationNTUinAndUidApi.getUinFromUid(uid) + if (uin.isNullOrEmpty()) { + createUnknownUidDialog(ctx, uid) + return + } else { + OpenProfileCard.openUserProfileCard(ctx, uin.toLong()) + } + } catch (e: Exception) { + FaultyDialog.show(ctx, e) + } + } + } + } + } + + private fun createAtSpanBySearch(text: String, atElements: List): SpannableString { + val ssb = SpannableString(text) + for (at in atElements) { + if (at.content.length >= 2) { + val uid = at.atNtUid + val start = text.indexOf(at.content) + if (start == -1) continue + val end = start + at.content.length + ssb.setSpan(createClickSpanForUid(uid), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + } + return ssb + } + override fun onGetViewNt(rootView: ViewGroup, chatMessage: MsgRecord, param: XC_MethodHook.MethodHookParam) { if (!isEnabled) return - - Log.i("----------------onGetViewNt") - Log.i(chatMessage.toString()) - //if (!isEnabled || 1 != chatMessage.chatType) return + if (chatMessage.chatType != ChatTypeConstants.GROUP) return + // MIX 2, REPLY 9, STRUCT_LONG_MSG 12 + val msgType = chatMessage.msgType + if (msgType != 2 && msgType != 9 && msgType != 12) return val elements = chatMessage.elements ?: return + val atElements = mutableListOf() elements.forEach { if (it.textElement != null && it.textElement.atType != 0) { - Log.i(it.textElement.content) + atElements.add(it.textElement) } } + if (atElements.isEmpty()) { + return + } val tv = rootView.findHostView("ex1") - //tv?.text = "12345" + // TODO 2023-07-16 有时候 ex1 会为空 + tv?.let { + val spannable = createAtSpanBySearch(tv.text.toString(), atElements) + tv.text = spannable + } } private fun copeAtInfo(textView: TextView, atList: List<*>) {