diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/CommentsFilterBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/CommentsFilterBarFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt index 2fc6e94f5..fc48bbb0c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/CommentsFilterBarFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt @@ -8,10 +8,10 @@ import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -@Name("comment-actionbar-fingerprint") +@Name("litho-ui-fingerprint") @ThemeCompatibility @Version("0.0.1") -object CommentsFilterBarFingerprint : MethodFingerprint( +object LithoThemeFingerprint : MethodFingerprint( "V", AccessFlags.PROTECTED or AccessFlags.FINAL, listOf("L"), listOf( Opcode.APUT, Opcode.NEW_INSTANCE, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/CommentsFilterBarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/LithoThemePatch.kt similarity index 51% rename from src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/CommentsFilterBarPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/LithoThemePatch.kt index d89a66366..4e91d15c3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/CommentsFilterBarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/LithoThemePatch.kt @@ -11,36 +11,27 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility -import app.revanced.patches.youtube.layout.theme.fingerprints.CommentsFilterBarFingerprint +import app.revanced.patches.youtube.layout.theme.fingerprints.LithoThemeFingerprint -@Name("comment-filter-bar-theme") -@Description("Applies custom theming to comments filter action bar.") +@Name("litho-components-theme") +@Description("Applies a custom theme to litho components.") @ThemeCompatibility @Version("0.0.1") -class CommentsFilterBarPatch : BytecodePatch( +class LithoThemePatch : BytecodePatch( listOf( - CommentsFilterBarFingerprint + LithoThemeFingerprint ) ) { override fun execute(context: BytecodeContext): PatchResult { - val result = CommentsFilterBarFingerprint.result!! + val result = LithoThemeFingerprint.result!! val method = result.mutableMethod val patchIndex = result.scanResult.patternScanResult!!.endIndex - 1 method.addInstructions( patchIndex, """ - invoke-static {}, Lapp/revanced/integrations/utils/ThemeHelper;->isDarkTheme()Z - move-result v2 - if-nez v2, :comments_filter_white - const v1, -0x1 - if-ne v1, p1, :comments_filter_white - const/4 p1, 0x0 - :comments_filter_white - if-eqz v2, :comments_filter_dark - const v1, -0xdededf - if-ne v1, p1, :comments_filter_dark - const/4 p1, 0x0 - """, listOf(ExternalLabel("comments_filter_dark", method.instruction(patchIndex))) + invoke-static {p1}, Lapp/revanced/integrations/patches/LithoThemePatch;->applyLithoTheme(I)I + move-result p1 + """ ) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt index a9d527bcb..ce876f1a1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt @@ -14,7 +14,7 @@ import app.revanced.util.resources.ResourceUtils.copyResources import org.w3c.dom.Element @Patch -@DependsOn([CommentsFilterBarPatch::class, FixLocaleConfigErrorPatch::class]) +@DependsOn([LithoThemePatch::class, FixLocaleConfigErrorPatch::class]) @Name("theme") @Description("Applies a custom theme.") @ThemeCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt deleted file mode 100644 index 5ca32c8c2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility - -// TODO: This is more of a class fingerprint than a method fingerprint. -// Convert to a class fingerprint whenever possible. -@Name("revanced-settings-activity-fingerprint") -@SettingsCompatibility -@Version("0.0.1") -object ReVancedSettingsActivityFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("ReVancedSettingActivity;") && methodDef.name == "initializeSettings" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt new file mode 100644 index 000000000..7c612a70b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("theme-setter-app-fingerprint") +@SettingsCompatibility +@Version("0.0.1") +object ThemeSetterAppFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L", "L"), listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.IF_NE, + Opcode.CONST, + Opcode.GOTO, + Opcode.CONST, + Opcode.INVOKE_DIRECT, + Opcode.RETURN_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.IF_NE, + Opcode.CONST, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt similarity index 74% rename from src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt index b1ffa601b..366e67458 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt @@ -5,18 +5,19 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.WideLiteralInstruction -@Name("theme-setter-fingerprint") +@Name("theme-setter-system-fingerprint") @SettingsCompatibility @Version("0.0.1") -object ThemeSetterFingerprint : MethodFingerprint( +object ThemeSetterSystemFingerprint : MethodFingerprint( "L", opcodes = listOf(Opcode.RETURN_OBJECT), customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { - it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == SettingsPatch.appearanceStringId + it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == SettingsResourcePatch.appearanceStringId } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt index 1cf7833b0..a5751d2e8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt @@ -11,15 +11,12 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.toInstruction import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.mapping.patch.ResourceMappingResourcePatch import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ReVancedSettingsActivityFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterFingerprint +import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterAppFingerprint +import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference -import app.revanced.patches.youtube.misc.settings.framework.components.impl.ArrayResource import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference import app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource @@ -39,64 +36,92 @@ import java.io.Closeable @SettingsCompatibility @Version("0.0.1") class SettingsPatch : BytecodePatch( - listOf(LicenseActivityFingerprint, ReVancedSettingsActivityFingerprint, ThemeSetterFingerprint) + listOf(LicenseActivityFingerprint, ThemeSetterSystemFingerprint, ThemeSetterAppFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - val licenseActivityResult = LicenseActivityFingerprint.result!! - val settingsResult = ReVancedSettingsActivityFingerprint.result!! - val themeSetterResult = ThemeSetterFingerprint.result!! + fun buildInvokeInstructionsString( + registers: String = "v0", + classDescriptor: String = THEME_HELPER_DESCRIPTOR, + methodName: String = SET_THEME_METHOD_NAME, + parameters: String = "Ljava/lang/Object;" + ) = "invoke-static {$registers}, $classDescriptor->$methodName($parameters)V" - val licenseActivityClass = licenseActivityResult.mutableClass - val settingsClass = settingsResult.mutableClass + // apply the current theme of the settings page + with(ThemeSetterSystemFingerprint.result!!) { + with(mutableMethod) { + val call = buildInvokeInstructionsString() - val onCreate = licenseActivityResult.mutableMethod - val setThemeMethodName = "setTheme" - val initializeSettings = settingsResult.mutableMethod + addInstruction( + scanResult.patternScanResult!!.startIndex, + call + ) - val setThemeInstruction = - "invoke-static {v0}, Lapp/revanced/integrations/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V".toInstruction( - themeSetterResult.mutableMethod - ) - - // add instructions to set the theme of the settings activity - themeSetterResult.mutableMethod.implementation!!.let { - it.addInstruction( - themeSetterResult.scanResult.patternScanResult!!.startIndex, - setThemeInstruction - ) - - it.addInstruction( - it.instructions.size - 1, // add before return - setThemeInstruction - ) + addInstruction( + mutableMethod.implementation!!.instructions.size - 1, + call + ) + } } - // add the setTheme call to the onCreate method to not affect the offsets - onCreate.addInstructions( - 1, - """ - invoke-static { p0 }, ${settingsClass.type}->${initializeSettings.name}(${licenseActivityClass.type})V - return-void - """ - ) + // set the theme based on the preference of the app + with(ThemeSetterAppFingerprint.result!!) { + with(mutableMethod) { + fun buildInstructionsString(theme: Int) = """ + const/4 v0, 0x$theme + ${buildInvokeInstructionsString(parameters = "I")} + """ - // add the initializeSettings call to the onCreate method - onCreate.addInstruction( - 0, - "invoke-static { p0 }, ${settingsClass.type}->$setThemeMethodName(${licenseActivityClass.type})V" - ) + addInstructions( + scanResult.patternScanResult!!.endIndex + 1, + buildInstructionsString(1) + ) - // get rid of, now, useless overridden methods - licenseActivityResult.mutableClass.methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) } + addInstructions( + mutableMethod.implementation!!.instructions.size - 2, + buildInstructionsString(0) + ) + } + } + + // set the theme based on the preference of the device + with(LicenseActivityFingerprint.result!!) licenseActivity@{ + with(mutableMethod) { + fun buildSettingsActivityInvokeString( + registers: String = "p0", + classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR, + methodName: String = "initializeSettings", + parameters: String = this@licenseActivity.mutableClass.type + ) = buildInvokeInstructionsString(registers, classDescriptor, methodName, parameters) + + // initialize the settings + addInstructions( + 1, + """ + ${buildSettingsActivityInvokeString()} + return-void + """ + ) + + // set the current theme + addInstruction(0, buildSettingsActivityInvokeString(methodName = "setTheme")) + } + + // remove method overrides + with(mutableClass) { + methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) } + } + } return PatchResultSuccess() } internal companion object { - // TODO: hide this somehow - var appearanceStringId: Long = ResourceMappingResourcePatch.resourceMappings.find { - it.type == "string" && it.name == "app_theme_appearance_dark" - }!!.id + private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations" + + private const val SETTINGS_ACTIVITY_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settingsmenu/ReVancedSettingActivity;" + + private const val THEME_HELPER_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/utils/ThemeHelper;" + private const val SET_THEME_METHOD_NAME = "setTheme" fun addString(identifier: String, value: String, formatted: Boolean = true) = SettingsResourcePatch.addString(identifier, value, formatted) @@ -107,9 +132,6 @@ class SettingsPatch : BytecodePatch( fun addPreference(preference: Preference) = SettingsResourcePatch.addPreference(preference) - fun addArray(arrayResource: ArrayResource) = - SettingsResourcePatch.addArray(arrayResource) - fun renameIntentsTargetPackage(newPackage: String) { SettingsResourcePatch.overrideIntentsTargetPackage = newPackage } @@ -152,4 +174,4 @@ class SettingsPatch : BytecodePatch( override fun close() = PreferenceScreen.values().forEach(PreferenceScreen::close) -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt index 93177c2b7..d6ab6abc7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt @@ -24,8 +24,14 @@ import org.w3c.dom.Node @DependsOn([FixLocaleConfigErrorPatch::class, ResourceMappingResourcePatch::class]) @Version("0.0.1") class SettingsResourcePatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { + /* + * used by a fingerprint of SettingsPatch + */ + appearanceStringId = ResourceMappingResourcePatch.resourceMappings.find { + it.type == "string" && it.name == "app_theme_appearance_dark" + }!!.id + /* * create missing directory for the resources */ @@ -84,6 +90,12 @@ class SettingsResourcePatch : ResourcePatch { internal companion object { + // Used by a fingerprint of SettingsPatch + // this field is located in the SettingsResourcePatch + // because if it were to be defined in the SettingsPatch companion object, + // the companion object could be initialized before ResourceMappingResourcePatch has executed. + internal var appearanceStringId: Long = -1 + // if this is not null, all intents will be renamed to this var overrideIntentsTargetPackage: String? = null