Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(YouTube Music - AMOLED black theme): Add AMOLED black theme patch #4258

Draft
wants to merge 7 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
ILoveOpenSourceApplications marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package app.revanced.extension.music;

import android.app.Activity;
import android.graphics.Color;

import androidx.annotation.Nullable;

import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;

public class ThemeHelper {
@Nullable
private static Integer darkThemeColor;
private static int themeValue;

/**
* Injection point.
*/
@SuppressWarnings("unused")
public static void setTheme(Enum<?> value) {
final int newOrdinalValue = value.ordinal();
if (themeValue != newOrdinalValue) {
themeValue = newOrdinalValue;
Logger.printDebug(() -> "Theme value: " + newOrdinalValue);
}
}

public static boolean isDarkTheme() {
return themeValue == 1;
}

public static void setActivityTheme(Activity activity) {
final var theme = "Theme.Music.Settings.Dark";
activity.setTheme(Utils.getResourceIdentifier(theme, "style"));
}

/**
* Injection point.
*/
@SuppressWarnings("SameReturnValue")
private static String darkThemeResourceName() {
// Value is changed by Theme patch, if included.
return "@color/yt_black3";
}

/**
* @return The dark theme color as specified by the Theme patch (if included),
* or the dark mode background color unpatched YT Music uses.
*/
public static int getDarkThemeColor() {
if (darkThemeColor == null) {
darkThemeColor = getColorInt(darkThemeResourceName());
}
return darkThemeColor;
}

private static int getColorInt(String colorString) {
if (colorString.startsWith("#")) {
return Color.parseColor(colorString);
}
return Utils.getResourceColor(colorString);
}

public static int getBackgroundColor() {
return getDarkThemeColor();
}

public static int getForegroundColor() {
// Since we are not using a light theme, return a contrasting color.
return Color.WHITE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package app.revanced.patches.music.layout.amoledblacktheme

import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.smali.toInstructions
import org.w3c.dom.Element

val amoledBlackThemePatch = bytecodePatch(
ILoveOpenSourceApplications marked this conversation as resolved.
Show resolved Hide resolved
name = "AMOLED black theme",
description = "Applies an AMOLED black theme for YouTube Music.",
) {
val amoledBlackColor = "@android:color/black"

dependsOn(
resourcePatch {
execute {
document("res/values/colors.xml").use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element

for (i in 0 until resourcesNode.childNodes.length) {
val node = resourcesNode.childNodes.item(i) as? Element ?: continue

node.textContent = when (node.getAttribute("name")) {
"yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3",
"yt_black4", "yt_status_bar_background_dark", "ytm_color_grey_12", "material_grey_850" -> amoledBlackColor

else -> continue
}
}
}

// Set the navigation bar color to black
document("res/values/colors.xml").use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element

resourcesNode.appendChild(
document.createElement("color").apply {
setAttribute("name", "navigation_bar_color")
textContent = amoledBlackColor
}
)
}
}
}
)

compatibleWith("com.google.android.apps.youtube.music")

execute {
// Modify the dark theme color
themeHelperFingerprint.method.apply {
val instructions = """
const-string v0, "$amoledBlackColor"
return-object v0
""".toInstructions()

addInstructions(themeHelperFingerprint.patternMatch!!.startIndex, instructions)
}

// Modify the navigation bar color
themeHelperFingerprint.method.apply {
val instructions = """
const-string v0, "$amoledBlackColor"
return-object v0
""".toInstructions()

addInstructions(themeHelperFingerprint.patternMatch!!.startIndex, instructions)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package app.revanced.patches.music.layout.amoledblacktheme

import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

internal val themeHelperFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
opcodes(
Opcode.CONST_STRING,
Opcode.RETURN_OBJECT
)
custom { method, _ ->
(method.name == "darkThemeResourceName" || method.name == "navigationBarColorResourceName") &&
method.definingClass == "Lapp/revanced/extension/music/ThemeHelper;"
}
}
Loading