Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,53 +1,101 @@
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;

@SuppressWarnings("unused")
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;
}

/**
* @return The attribute id of this header logo, or NULL if the logo should not be replaced.
*/
@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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,26 @@ 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;"

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"
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -379,16 +380,13 @@ val hideLayoutComponentsPatch = bytecodePatch(
findInstructionIndicesReversedOrThrow {
getReference<MethodReference>()?.name == "setImageDrawable"
}.forEach { insertIndex ->
val register = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
val drawableRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
val imageViewRegister = getInstruction<FiveRegisterInstruction>(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"
)
}
}
Expand Down
Loading