From db0298b9f0cc6066974630d29812a2e8a11e7262 Mon Sep 17 00:00:00 2001 From: Swakshan Date: Fri, 19 Apr 2024 21:08:56 +0530 Subject: [PATCH] feat(Twitter): Added `Profile tabs customisation` --- .../profiletabs/CustomiseProfileTabsPatch.kt | 86 +++++++++++++++++++ .../twitter/misc/settings/SettingsPatch.kt | 1 + .../misc/settings/SettingsResourcePatch.kt | 8 +- .../twitter/settings/values-v21/strings.xml | 4 +- .../twitter/settings/values/arrays.xml | 15 ++++ .../twitter/settings/values/strings.xml | 3 + 6 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/crimera/patches/twitter/misc/customize/profiletabs/CustomiseProfileTabsPatch.kt create mode 100644 src/main/resources/twitter/settings/values/arrays.xml diff --git a/src/main/kotlin/crimera/patches/twitter/misc/customize/profiletabs/CustomiseProfileTabsPatch.kt b/src/main/kotlin/crimera/patches/twitter/misc/customize/profiletabs/CustomiseProfileTabsPatch.kt new file mode 100644 index 00000000..6ae2bef7 --- /dev/null +++ b/src/main/kotlin/crimera/patches/twitter/misc/customize/profiletabs/CustomiseProfileTabsPatch.kt @@ -0,0 +1,86 @@ +package crimera.patches.twitter.misc.customize.profiletabs + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions +import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.smali.ExternalLabel +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import crimera.patches.twitter.misc.settings.SettingsPatch +import crimera.patches.twitter.misc.settings.fingerprints.SettingsStatusLoadFingerprint + +object CustomiseProfileTabsFingerprint:MethodFingerprint( + returnType = "Ljava/util/ArrayList;", + strings = listOf( + "fragment_page_number", + "arg_is_unlimited_timeline", + "statuses_count", + "tweets", + "blue_business_affiliates_list_consumption_ui_enabled", + ) +) + +@Patch( + name = "Customize profile tabs", + dependencies = [SettingsPatch::class], + compatiblePackages = [CompatiblePackage("com.twitter.android")], + use = false, + requiresIntegrations = true +) +@Suppress("unused") +object CustomiseProfileTabsPatch:BytecodePatch( + setOf(CustomiseProfileTabsFingerprint,SettingsStatusLoadFingerprint) +){ + override fun execute(context: BytecodeContext) { + val results = CustomiseProfileTabsFingerprint.result + ?:throw PatchException("CustomiseProfileTabsFingerprint not found") + + val method = results.mutableMethod + val instructions = method.getInstructions() + + val returnObj_loc = instructions.last { it.opcode == Opcode.RETURN_OBJECT }.location.index + val r0 = method.getInstruction(returnObj_loc).registerA + + val METHOD = """ + invoke-static {v$r0}, ${SettingsPatch.CUSTOMISE_DESCRIPTOR}/ProfileTabs;->a(Ljava/util/ArrayList;)Ljava/util/ArrayList; + move-result-object v$r0 + """.trimIndent() + + method.addInstructions(returnObj_loc,METHOD) + + val last_if_eqz = instructions.last { it.opcode == Opcode.IF_EQZ }.location.index + val r1 = method.getInstruction(last_if_eqz).registerA + + val last_if_nez_loc = instructions.last { it.opcode == Opcode.IF_NEZ }.location.index + val r2 = method.getInstruction(last_if_nez_loc).registerA + + //it works dont ask me how + method.removeInstruction(last_if_eqz) + method.removeInstruction(last_if_eqz) + method.removeInstruction(last_if_eqz) + + method.addInstructionsWithLabels(last_if_eqz, + """ + if-eqz v$r1, :check2 + const/4 v$r2, 0x1 + :check2 + if-nez v$r2, :check1 + """.trimIndent(), ExternalLabel("check1",instructions.last { it.opcode == Opcode.INVOKE_STATIC }) + ) + + SettingsStatusLoadFingerprint.result!!.mutableMethod.addInstruction( + 0, + "${SettingsPatch.SSTS_DESCRIPTOR}->profileTabCustomisation()V" + ) + //end + } +} \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt b/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt index 09fd27f7..b88f2ff4 100644 --- a/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt +++ b/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt @@ -30,6 +30,7 @@ object SettingsPatch : BytecodePatch( private const val UTILS_DESCRIPTOR = "$INTEGRATIONS_PACKAGE/Utils" const val PREF_DESCRIPTOR = "$INTEGRATIONS_PACKAGE/Pref" const val PATCHES_DESCRIPTOR = "$INTEGRATIONS_PACKAGE/patches" + const val CUSTOMISE_DESCRIPTOR = "$PATCHES_DESCRIPTOR/customise" private const val ADD_PREF_DESCRIPTOR = "$UTILS_DESCRIPTOR;->addPref([Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;" const val SSTS_DESCRIPTOR = "invoke-static {}, $INTEGRATIONS_PACKAGE/settings/SettingsStatus;" const val FSTS_DESCRIPTOR = "invoke-static {}, $INTEGRATIONS_PACKAGE/patches/FeatureSwitchPatch;" diff --git a/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsResourcePatch.kt b/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsResourcePatch.kt index 235df3e7..279398b5 100644 --- a/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsResourcePatch.kt +++ b/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsResourcePatch.kt @@ -57,10 +57,12 @@ object SettingsResourcePatch: ResourcePatch() { //credits @inotia00 context.copyXmlNode("twitter/settings", "values/strings.xml", "resources") + context.copyXmlNode("twitter/settings", "values/arrays.xml", "resources") /** * create directory for the untranslated language resources */ + //Strings val languages = arrayOf( "ar", "ja", @@ -70,8 +72,8 @@ object SettingsResourcePatch: ResourcePatch() { "ru", "pl", "pt-rBR", - "v21", - "tr" + "tr", + "v21" ).map { "values-$it" } languages.forEach { @@ -82,5 +84,7 @@ object SettingsResourcePatch: ResourcePatch() { context.copyResources("twitter/settings", ResourceGroup(it, "strings.xml")) } } + + //end } } diff --git a/src/main/resources/twitter/settings/values-v21/strings.xml b/src/main/resources/twitter/settings/values-v21/strings.xml index f0be9549..935e408e 100644 --- a/src/main/resources/twitter/settings/values-v21/strings.xml +++ b/src/main/resources/twitter/settings/values-v21/strings.xml @@ -1,6 +1,6 @@ - - Piko Mod Settings + + Piko mod Settings Feature flags \ No newline at end of file diff --git a/src/main/resources/twitter/settings/values/arrays.xml b/src/main/resources/twitter/settings/values/arrays.xml new file mode 100644 index 00000000..3ef9c400 --- /dev/null +++ b/src/main/resources/twitter/settings/values/arrays.xml @@ -0,0 +1,15 @@ + + + + + + @string/profile_tab_title_timeline + @string/profile_tab_title_timeline_tweets_and_replies_sentence_case + @string/profile_tab_title_affiliates + @string/profile_tab_title_timeline_super_follow_tweets + @string/profile_tab_title_highlights + @string/profile_tab_title_articles + @string/profile_tab_title_media + @string/profile_tab_title_likes + + \ No newline at end of file diff --git a/src/main/resources/twitter/settings/values/strings.xml b/src/main/resources/twitter/settings/values/strings.xml index eff3d9e0..cfee85f0 100644 --- a/src/main/resources/twitter/settings/values/strings.xml +++ b/src/main/resources/twitter/settings/values/strings.xml @@ -50,6 +50,9 @@ Hide immersive player Removes swipe up for more videos in video player + Customization + Profile tabs + Backup and restore Export preferences Export feature flags