From 785cd19405e08c4c3a37a47e15b83d31db8e3b75 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 12 Jul 2025 17:22:45 +0400 Subject: [PATCH] fix(YouTube - Hide layout components): Show custom header logo if 'Hide YouTube Doodles' is enabled --- .../youtube/patches/ChangeHeaderPatch.java | 84 +++++++++++++++---- .../components/LayoutComponentsFilter.java | 14 ++-- .../branding/header/ChangeHeaderPatch.kt | 14 +++- .../hide/general/HideLayoutComponentsPatch.kt | 14 ++-- 4 files changed, 92 insertions(+), 34 deletions(-) diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java index 12b1227fc7..ed5bcec07b 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java @@ -1,9 +1,12 @@ package app.revanced.extension.youtube.patches; +import android.graphics.drawable.Drawable; + import androidx.annotation.Nullable; import java.util.Objects; +import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.settings.Settings; @@ -11,18 +14,21 @@ public class ChangeHeaderPatch { public enum HeaderLogo { - DEFAULT(null), - REGULAR("ytWordmarkHeader"), - PREMIUM("ytPremiumWordmarkHeader"), - REVANCED("revanced_header_logo"), - REVANCED_MINIMAL("revanced_header_logo_minimal"), - CUSTOM("custom_header"); + DEFAULT(null, null), + REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"), + PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"), + REVANCED("revanced_header_logo", "revanced_header_logo"), + REVANCED_MINIMAL("revanced_header_logo_minimal", "revanced_header_logo_minimal"), + CUSTOM("custom_header", "custom_header"); @Nullable - private final String resourceName; + private final String attributeName; + @Nullable + private final String drawableName; - HeaderLogo(@Nullable String resourceName) { - this.resourceName = resourceName; + HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) { + this.attributeName = attributeName; + this.drawableName = drawableName; } /** @@ -30,24 +36,66 @@ public enum HeaderLogo { */ @Nullable private Integer getAttributeId() { - if (resourceName == null) { + if (attributeName == null) { + return null; + } + + final int identifier = Utils.getResourceIdentifier(attributeName, "attr"); + if (identifier == 0) { + // Identifier is zero if custom header setting was included in imported settings + // and a custom image was not included during patching. + Logger.printDebug(() -> "Could not find attribute: " + drawableName); + Settings.HEADER_LOGO.resetToDefault(); return null; } - final int identifier = Utils.getResourceIdentifier(resourceName, "attr"); - // Identifier is zero if custom header setting was included in imported settings - // and a custom image was not included during patching. - return identifier == 0 ? null : identifier; + return identifier; } - } - @Nullable - private static final Integer headerLogoResource = Settings.HEADER_LOGO.get().getAttributeId(); + @Nullable + public Drawable getDrawable() { + if (drawableName == null) { + return null; + } + + String drawableFullName = drawableName + (Utils.isDarkModeEnabled() + ? "_dark" + : "_light"); + + final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable"); + if (identifier == 0) { + Logger.printDebug(() -> "Could not find drawable: " + drawableFullName); + Settings.HEADER_LOGO.resetToDefault(); + return null; + } + return Utils.getContext().getDrawable(identifier); + } + } /** * Injection point. */ public static int getHeaderAttributeId(int original) { - return Objects.requireNonNullElse(headerLogoResource, original); + return Objects.requireNonNullElse(Settings.HEADER_LOGO.get().getAttributeId(), original); + } + + public static Drawable getDrawable(Drawable original) { + Drawable logo = Settings.HEADER_LOGO.get().getDrawable(); + if (logo != null) { + return logo; + } + + // TODO: If 'Hide Doodles' is enabled, this will force the regular logo regardless + // what account the user has. This can be improved the next time a Doodle is + // active and the attribute id is passed to this method so the correct + // regular/premium logo is returned. + logo = HeaderLogo.REGULAR.getDrawable(); + if (logo != null) { + return logo; + } + + // Should never happen. + Logger.printException(() -> "Could not find regular header logo resource"); + return original; } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java index 87ba674505..c4313b51de 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java @@ -4,12 +4,14 @@ import android.graphics.drawable.Drawable; import android.view.View; +import android.widget.ImageView; import androidx.annotation.Nullable; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.youtube.patches.ChangeHeaderPatch; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.NavigationBar; import app.revanced.extension.youtube.shared.PlayerType; @@ -437,13 +439,11 @@ public static void hideInRelatedVideos(View chipView) { /** * Injection point. */ - @Nullable - public static Drawable hideYoodles(Drawable animatedYoodle) { - if (HIDE_DOODLES_ENABLED) { - return null; - } - - return animatedYoodle; + public static void setDoodleDrawable(ImageView imageView, Drawable original) { + Drawable replacement = HIDE_DOODLES_ENABLED + ? ChangeHeaderPatch.getDrawable(original) + : original; + imageView.setImageDrawable(replacement); } private static final boolean HIDE_SHOW_MORE_BUTTON_ENABLED = Settings.HIDE_SHOW_MORE_BUTTON.get(); diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt index c910d136b1..cd20455504 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -22,6 +22,8 @@ import app.revanced.util.forEachLiteralValueInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import java.io.File +private val variants = arrayOf("light", "dark") + private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;" @@ -29,6 +31,17 @@ private val changeHeaderBytecodePatch = bytecodePatch { dependsOn(resourceMappingPatch) execute { + // Resources are not used during patching, but extension code uses these + // images so verify they exist. + arrayOf( + "yt_ringo2_wordmark_header", + "yt_ringo2_premium_wordmark_header" + ).forEach { resource -> + variants.forEach { theme -> + resourceMappings["drawable", resource + "_" + theme] + } + } + arrayOf( "ytWordmarkHeader", "ytPremiumWordmarkHeader" @@ -57,7 +70,6 @@ private val targetResourceDirectoryNames = mapOf( "mdpi" to "129px x 48px" ).mapKeys { (dpi, _) -> "drawable-$dpi" } -private val variants = arrayOf("light", "dark") /** * Header logos built into this patch. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index e81d05a100..f81d10ca40 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -8,6 +8,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.smali.ExternalLabel @@ -379,16 +380,13 @@ val hideLayoutComponentsPatch = bytecodePatch( findInstructionIndicesReversedOrThrow { getReference()?.name == "setImageDrawable" }.forEach { insertIndex -> - val register = getInstruction(insertIndex).registerD + val drawableRegister = getInstruction(insertIndex).registerD + val imageViewRegister = getInstruction(insertIndex).registerC - addInstructionsWithLabels( + replaceInstruction( insertIndex, - """ - invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideYoodles(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable; - move-result-object v$register - if-eqz v$register, :hide - """, - ExternalLabel("hide", getInstruction(insertIndex + 1)), + "invoke-static { v$imageViewRegister, v$drawableRegister }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->" + + "setDoodleDrawable(Landroid/widget/ImageView;Landroid/graphics/drawable/Drawable;)V" ) } }