From bce750dce5f56035de2f93d1bbe27921eecefe6f Mon Sep 17 00:00:00 2001 From: 5ec1cff Date: Sun, 19 May 2024 22:17:37 +0800 Subject: [PATCH] feat: add ShowIdInProfile --- .../ioctl/tmoe/fragment/SettingsFragment.kt | 40 ++++++++- .../hook/core/ProfileActivityRowHook.java | 9 ++- .../tmoe/hook/core/SettingEntryHook.java | 20 +---- .../ioctl/tmoe/hook/func/ShowIdInProfile.kt | 81 +++++++++++++++++++ app/src/main/res/values-zh-rCN/strings.xml | 5 ++ app/src/main/res/values/strings.xml | 5 ++ 6 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/cc/ioctl/tmoe/hook/func/ShowIdInProfile.kt diff --git a/app/src/main/java/cc/ioctl/tmoe/fragment/SettingsFragment.kt b/app/src/main/java/cc/ioctl/tmoe/fragment/SettingsFragment.kt index 975f6b6e..d55a31b0 100644 --- a/app/src/main/java/cc/ioctl/tmoe/fragment/SettingsFragment.kt +++ b/app/src/main/java/cc/ioctl/tmoe/fragment/SettingsFragment.kt @@ -2,7 +2,41 @@ package cc.ioctl.tmoe.fragment import android.widget.Toast import cc.ioctl.tmoe.R -import cc.ioctl.tmoe.hook.func.* +import cc.ioctl.tmoe.hook.func.AddInfoContainer +import cc.ioctl.tmoe.hook.func.AddReloadMsgBtn +import cc.ioctl.tmoe.hook.func.AddSubItemChannel +import cc.ioctl.tmoe.hook.func.AntiAntiCopy +import cc.ioctl.tmoe.hook.func.AntiAntiForward +import cc.ioctl.tmoe.hook.func.ChannelDetailNumbers +import cc.ioctl.tmoe.hook.func.DatabaseCorruptionWarning +import cc.ioctl.tmoe.hook.func.DisableInstantCamera +import cc.ioctl.tmoe.hook.func.DisablePremiumStickerAnimation +import cc.ioctl.tmoe.hook.func.DumpGroupMember +import cc.ioctl.tmoe.hook.func.EnableDebugMode +import cc.ioctl.tmoe.hook.func.ExtendedOfflineSearch +import cc.ioctl.tmoe.hook.func.ForceBlurChatAvailable +import cc.ioctl.tmoe.hook.func.FuckTrackingHook +import cc.ioctl.tmoe.hook.func.HidePhoneNumber +import cc.ioctl.tmoe.hook.func.HidePremiumStickerSetTab +import cc.ioctl.tmoe.hook.func.HideServiceStories +import cc.ioctl.tmoe.hook.func.HideSponsoredMsg +import cc.ioctl.tmoe.hook.func.HideUserAvatar +import cc.ioctl.tmoe.hook.func.HistoricGroupMemberRecord +import cc.ioctl.tmoe.hook.func.HistoricalNewsOption +import cc.ioctl.tmoe.hook.func.KeepVideoMuted +import cc.ioctl.tmoe.hook.func.LocalGroupMemberList +import cc.ioctl.tmoe.hook.func.ProhibitChannelSwitching +import cc.ioctl.tmoe.hook.func.ProhibitChatGreetings +import cc.ioctl.tmoe.hook.func.ProhibitEnableReactions +import cc.ioctl.tmoe.hook.func.ProhibitSpoilers +import cc.ioctl.tmoe.hook.func.SendCommand +import cc.ioctl.tmoe.hook.func.ShowExactLastSeenTime +import cc.ioctl.tmoe.hook.func.ShowIdInProfile +import cc.ioctl.tmoe.hook.func.ShowMsgId +import cc.ioctl.tmoe.hook.func.TgnetLogControlStartupApplyHelper +import cc.ioctl.tmoe.hook.func.TgnetLogController +import cc.ioctl.tmoe.hook.func.UseSystemEmoji +import cc.ioctl.tmoe.hook.func.ViewTopicAsMsgByDefault import cc.ioctl.tmoe.ui.LocaleController import cc.ioctl.tmoe.ui.dsl.BaseHierarchyFragment import cc.ioctl.tmoe.ui.dsl.HierarchyDescription @@ -128,6 +162,10 @@ class SettingsFragment : BaseHierarchyFragment() { functionSwitch( HideServiceStories, "HideServiceStories", R.string.HideServiceStories ) + functionSwitch( + ShowIdInProfile, "ShowIdInProfile", R.string.ShowIdInProfile, + "ShowIdInProfileDesc", R.string.ShowIdInProfileDesc + ) } category("LostMsgMitigation", R.string.LostMsgMitigation) { functionSwitch( diff --git a/app/src/main/java/cc/ioctl/tmoe/hook/core/ProfileActivityRowHook.java b/app/src/main/java/cc/ioctl/tmoe/hook/core/ProfileActivityRowHook.java index f56a0cb2..67820ee4 100644 --- a/app/src/main/java/cc/ioctl/tmoe/hook/core/ProfileActivityRowHook.java +++ b/app/src/main/java/cc/ioctl/tmoe/hook/core/ProfileActivityRowHook.java @@ -4,6 +4,7 @@ import android.os.Bundle; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.lang.reflect.Field; @@ -83,7 +84,7 @@ public interface Callback { * @param profileActivity * @return true if handled, otherwise false */ - boolean onBindViewHolder(String key, Object holder, Object adpater, Object profileActivity); + boolean onBindViewHolder(@NonNull String key, @NonNull Object holder, @NonNull Object adpater, @NonNull Object profileActivity); /** * getItemViewType @@ -92,7 +93,7 @@ public interface Callback { * @param profileActivity * @return type, -1 to skip */ - int getItemViewType(String key, Object adapter, Object profileActivity); + int getItemViewType(@NonNull String key, @NonNull Object adapter, @NonNull Object profileActivity); /** * @@ -100,9 +101,9 @@ public interface Callback { * @param adapter * @return true if handled, otherwise false */ - boolean onItemClicked(String key, Object adapter, Object profileActivity); + boolean onItemClicked(@NonNull String key, @NonNull Object adapter, @NonNull Object profileActivity); - void onInsertRow(RowManipulator manipulator, Object profileActivity); + void onInsertRow(@NonNull RowManipulator manipulator, @NonNull Object profileActivity); } private static final List sCallbacks = new ArrayList<>(); diff --git a/app/src/main/java/cc/ioctl/tmoe/hook/core/SettingEntryHook.java b/app/src/main/java/cc/ioctl/tmoe/hook/core/SettingEntryHook.java index e92ce51e..6f22a763 100644 --- a/app/src/main/java/cc/ioctl/tmoe/hook/core/SettingEntryHook.java +++ b/app/src/main/java/cc/ioctl/tmoe/hook/core/SettingEntryHook.java @@ -1,30 +1,18 @@ package cc.ioctl.tmoe.hook.core; -import android.content.Context; -import android.os.Bundle; import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.NonNull; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Objects; - import cc.ioctl.tmoe.R; import cc.ioctl.tmoe.fragment.SettingsFragment; import cc.ioctl.tmoe.lifecycle.Parasitics; import cc.ioctl.tmoe.rtti.ProxyFragmentRttiHandler; import cc.ioctl.tmoe.ui.LocaleController; import cc.ioctl.tmoe.util.HostInfo; -import cc.ioctl.tmoe.util.Initiator; import cc.ioctl.tmoe.util.Reflex; import cc.ioctl.tmoe.util.Utils; -import de.robv.android.xposed.XC_MethodHook; -import de.robv.android.xposed.XposedBridge; public class SettingEntryHook implements Initializable, ProfileActivityRowHook.Callback { public static final SettingEntryHook INSTANCE = new SettingEntryHook(); @@ -54,7 +42,7 @@ private static void presentTMoeSettingsFragment(@NonNull Object parentFragment) } @Override - public boolean onBindViewHolder(String key, Object holder, Object adpater, Object profileActivity) { + public boolean onBindViewHolder(@NonNull String key, @NonNull Object holder, @NonNull Object adpater, @NonNull Object profileActivity) { if (!TMOE_SETTINGS_ROW.equals(key)) return false; FrameLayout textCell = (FrameLayout) Reflex.getInstanceObjectOrNull(holder, "itemView"); if (textCell != null) { @@ -83,13 +71,13 @@ public boolean onBindViewHolder(String key, Object holder, Object adpater, Objec } @Override - public int getItemViewType(String key, Object adapter, Object profileActivity) { + public int getItemViewType(@NonNull String key, @NonNull Object adapter, @NonNull Object profileActivity) { if (TMOE_SETTINGS_ROW.equals(key)) return 4; return -1; } @Override - public boolean onItemClicked(String key, Object adapter, Object profileActivity) { + public boolean onItemClicked(@NonNull String key, @NonNull Object adapter, @NonNull Object profileActivity) { if (TMOE_SETTINGS_ROW.equals(key)) { presentTMoeSettingsFragment(profileActivity); return false; @@ -98,7 +86,7 @@ public boolean onItemClicked(String key, Object adapter, Object profileActivity) } @Override - public void onInsertRow(ProfileActivityRowHook.RowManipulator manipulator, Object profileActivity) { + public void onInsertRow(@NonNull ProfileActivityRowHook.RowManipulator manipulator, @NonNull Object profileActivity) { // put our fields into the list just before the language row int targetRow = manipulator.getRowIdForField("languageRow"); if (targetRow <= 0) { diff --git a/app/src/main/java/cc/ioctl/tmoe/hook/func/ShowIdInProfile.kt b/app/src/main/java/cc/ioctl/tmoe/hook/func/ShowIdInProfile.kt new file mode 100644 index 00000000..fb2d35e9 --- /dev/null +++ b/app/src/main/java/cc/ioctl/tmoe/hook/func/ShowIdInProfile.kt @@ -0,0 +1,81 @@ +package cc.ioctl.tmoe.hook.func + +import android.content.ClipData +import android.content.ClipboardManager +import android.widget.FrameLayout +import android.widget.Toast +import cc.ioctl.tmoe.R +import cc.ioctl.tmoe.base.annotation.FunctionHookEntry +import cc.ioctl.tmoe.hook.base.CommonDynamicHook +import cc.ioctl.tmoe.hook.core.ProfileActivityRowHook +import cc.ioctl.tmoe.lifecycle.Parasitics +import cc.ioctl.tmoe.ui.LocaleController +import cc.ioctl.tmoe.util.HostInfo +import cc.ioctl.tmoe.util.Reflex +import de.robv.android.xposed.XposedHelpers + +@FunctionHookEntry +object ShowIdInProfile : CommonDynamicHook(), ProfileActivityRowHook.Callback { + private val rowName = "SHOW_ID_IN_PROFILE" + + override fun initOnce(): Boolean { + ProfileActivityRowHook.addCallback(this) + return true + } + + override fun onBindViewHolder( + key: String, + holder: Any, + adpater: Any, + profileActivity: Any + ): Boolean { + if (rowName != key) return false + (Reflex.getInstanceObjectOrNull(holder, "itemView") as? FrameLayout)?.let { textCell -> + Parasitics.injectModuleResources(HostInfo.getApplication().resources) + val userId = getUserId(profileActivity) + val realId = if (userId == 0L) getChatId(profileActivity) else userId + val isUser = userId != 0L + val title = if (isUser) LocaleController.getString("UserId", R.string.UserId) + else LocaleController.getString("GroupOrChannelId", R.string.GroupOrChannelId) + XposedHelpers.callMethod(textCell, "setTextAndValue", realId.toString(), title, false) + } + return true + } + + override fun getItemViewType(key: String, adapter: Any, profileActivity: Any): Int { + if (rowName == key) return 2 // VIEW_TYPE_TEXT_DETAIL + return -1 + } + + override fun onItemClicked(key: String, adapter: Any, profileActivity: Any): Boolean { + if (rowName != key) return false + val userId = getUserId(profileActivity) + val realId = if (userId == 0L) getChatId(profileActivity) else userId + val context = HostInfo.getApplication() + context.getSystemService(ClipboardManager::class.java) + .setPrimaryClip(ClipData.newPlainText("", realId.toString())) + Toast.makeText(context, LocaleController.getString("IdCopied", R.string.IdCopied), Toast.LENGTH_SHORT).show() + return true + } + + override fun onInsertRow( + manipulator: ProfileActivityRowHook.RowManipulator, + profileActivity: Any + ) { + var row = manipulator.getRowIdForField("infoHeaderRow") + row = if (row == -1) 1 else row + 1 + manipulator.insertRowAtPosition(rowName, row) + } + + private fun getUserId(profileActivity: Any): Long { + return XposedHelpers.getObjectField(profileActivity, "userId") as Long + } + + private fun getChatId(profileActivity: Any): Long { + val chat = XposedHelpers.getObjectField(profileActivity, "currentChat") + if (chat != null) { + return XposedHelpers.getObjectField(chat, "id") as Long + } + return 0L + } +} \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 52953914..f9ed95c7 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -64,4 +64,9 @@ 仅对有权限查看用户最后上线时间的用户有效 禁用即时相机 隐藏“服务通知”的动态 + 资料页显示 ID + 群聊 / 频道 ID + 用户 ID + 已复制 + 在用户、频道和群聊资料页面显示 ID diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 83a25f7a..32d2ca0a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -92,4 +92,9 @@ If you click on an ad provided by Telegram, they will track it and might use it as the basis for personalizing the ad.This function is to disable it Disable Instant Camera Hide stories from service notifications + Show id in profile + Show id in profile page of user, chat or channel + Group / Channel ID + User ID + Copied