feat(YouTube Music): Add Change header patch
Co-authored-by: ILoveOpenSourceApplications <117499019+iloveopensourceapplications@users.noreply.github.com>
This commit is contained in:
parent
f10f5e2910
commit
f22ea5507d
9 changed files with 351 additions and 192 deletions
|
|
@ -0,0 +1,37 @@
|
|||
package app.revanced.extension.music.patches;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.ResourceType;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
public class ChangeHeaderPatch {
|
||||
public enum HeaderLogo {
|
||||
DEFAULT(null),
|
||||
REVANCED("revanced_header_dark"),
|
||||
CUSTOM("revanced_header_custom_dark");
|
||||
|
||||
private final String drawableName;
|
||||
|
||||
HeaderLogo(String drawableName) {
|
||||
this.drawableName = drawableName;
|
||||
}
|
||||
|
||||
private Integer getDrawableId() {
|
||||
if (drawableName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int id = Utils.getResourceIdentifier(ResourceType.DRAWABLE, drawableName);
|
||||
if (id == 0) {
|
||||
Logger.printException(() ->
|
||||
"Header drawable not found: " + drawableName
|
||||
);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package app.revanced.extension.music.settings;
|
|||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.music.patches.ChangeHeaderPatch.*;
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
|
||||
import app.revanced.extension.shared.settings.YouTubeAndMusicSettings;
|
||||
|
|
@ -28,6 +29,7 @@ public class Settings extends YouTubeAndMusicSettings {
|
|||
public static final BooleanSetting HIDE_NAVIGATION_BAR_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_upgrade_button", TRUE, true);
|
||||
public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_music_hide_navigation_bar", FALSE, true);
|
||||
public static final BooleanSetting HIDE_NAVIGATION_BAR_LABEL = new BooleanSetting("revanced_music_hide_navigation_bar_labels", FALSE, true);
|
||||
public static final EnumSetting<HeaderLogo> HEADER_LOGO = new EnumSetting<>("revnaced_header_logo", HeaderLogo.DEFAULT, true);
|
||||
|
||||
// Player
|
||||
public static final BooleanSetting CHANGE_MINIPLAYER_COLOR = new BooleanSetting("revanced_music_change_miniplayer_color", FALSE, true);
|
||||
|
|
|
|||
|
|
@ -11,4 +11,5 @@ public class YouTubeAndMusicSettings extends BaseSettings {
|
|||
// Miscellaneous
|
||||
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
|
||||
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ val customBrandingPatch = baseCustomBrandingPatch(
|
|||
mainActivityName = MUSIC_MAIN_ACTIVITY_NAME,
|
||||
activityAliasNameWithIntents = MUSIC_MAIN_ACTIVITY_NAME,
|
||||
preferenceScreen = PreferenceScreen.GENERAL,
|
||||
|
||||
block = {
|
||||
dependsOn(sharedExtensionPatch, disableSplashAnimationPatch)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package app.revanced.patches.music.layout.branding.header
|
||||
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.shared.layout.branding.header.changeHeaderPatch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceType
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
import app.revanced.util.forEachInstructionAsSequence
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
private val targetResourceDirectoryNames = mapOf(
|
||||
"drawable-hdpi" to "121x36 px",
|
||||
"drawable-xhdpi" to "160x48 px",
|
||||
"drawable-xxhdpi" to "240x72 px",
|
||||
"drawable-xxxhdpi" to "320x96 px"
|
||||
)
|
||||
|
||||
private val variants = arrayOf("dark")
|
||||
private val logoResourceNames = arrayOf("revanced_header_dark")
|
||||
|
||||
private val headerDrawableNames = arrayOf(
|
||||
"action_bar_logo_ringo2",
|
||||
"ytm_logo_ringo2"
|
||||
)
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/music/patches/ChangeHeaderPatch;"
|
||||
|
||||
private val changeHeaderBytecodePatch = bytecodePatch {
|
||||
dependsOn(resourceMappingPatch)
|
||||
|
||||
apply {
|
||||
headerDrawableNames.forEach { drawableName ->
|
||||
val drawableId = ResourceType.DRAWABLE[drawableName]
|
||||
|
||||
forEachInstructionAsSequence({ _, method, instruction, index ->
|
||||
if (instruction.wideLiteral != drawableId) return@forEachInstructionAsSequence null
|
||||
|
||||
val register = method.getInstruction<OneRegisterInstruction>(index).registerA
|
||||
|
||||
return@forEachInstructionAsSequence index to register
|
||||
}) { method, (index, register) ->
|
||||
method.addInstructions(
|
||||
index + 1,
|
||||
"""
|
||||
invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->getHeaderDrawableId(I)I
|
||||
move-result v$register
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
val changeHeaderPatch = changeHeaderPatch(
|
||||
targetResourceDirectoryNames = targetResourceDirectoryNames,
|
||||
changeHeaderBytecodePatch = changeHeaderBytecodePatch,
|
||||
logoResourceNames = logoResourceNames,
|
||||
variants = variants,
|
||||
preferenceScreen = PreferenceScreen.GENERAL,
|
||||
compatiblePackages = arrayOf(
|
||||
"com.google.android.apps.youtube.music" to setOf(
|
||||
"7.29.52",
|
||||
"8.10.52",
|
||||
"8.37.56",
|
||||
"8.40.54",
|
||||
),
|
||||
),
|
||||
resourcesAppId = "music",
|
||||
)
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
package app.revanced.patches.shared.layout.branding.header
|
||||
|
||||
import app.revanced.patcher.patch.Package
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.ResourcePatchContext
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.util.copyResources
|
||||
import java.io.File
|
||||
|
||||
internal const val CUSTOM_HEADER_RESOURCE_NAME = "revanced_header_custom"
|
||||
|
||||
@Suppress("unused")
|
||||
fun changeHeaderPatch(
|
||||
targetResourceDirectoryNames: Map<String, String>,
|
||||
changeHeaderBytecodePatch: Patch,
|
||||
vararg compatiblePackages: Package,
|
||||
variants: Array<String>,
|
||||
logoResourceNames: Array<String>,
|
||||
preferenceScreen: BasePreferenceScreen.Screen,
|
||||
resourcesAppId: String,
|
||||
applyBlock: ResourcePatchContext.() -> Unit = {},
|
||||
): Patch {
|
||||
val customHeaderResourceFileNames = variants.map { variant ->
|
||||
"${CUSTOM_HEADER_RESOURCE_NAME}_$variant.png"
|
||||
}.toTypedArray()
|
||||
|
||||
return resourcePatch(
|
||||
name = "Change header",
|
||||
description = "Adds an option to change the header logo in the top left corner of the app.",
|
||||
) {
|
||||
dependsOn(addResourcesPatch, changeHeaderBytecodePatch)
|
||||
|
||||
compatibleWith(packages = compatiblePackages)
|
||||
|
||||
val custom by stringOption(
|
||||
name = "Custom header logo",
|
||||
description = """
|
||||
Folder with images to use as a custom header logo.
|
||||
|
||||
The folder must contain one or more of the following folders, depending on the DPI of the device:
|
||||
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
|
||||
|
||||
Each of the folders must contain all of the following files:
|
||||
${customHeaderResourceFileNames.joinToString("\n")}
|
||||
|
||||
The image dimensions must be as follows:
|
||||
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
|
||||
""".trimIndentMultiline(),
|
||||
)
|
||||
|
||||
apply {
|
||||
addResources(resourcesAppId, "layout.branding.header.changeHeaderPatch")
|
||||
|
||||
preferenceScreen.addPreferences(
|
||||
if (custom == null) {
|
||||
ListPreference("revanced_header_logo")
|
||||
} else {
|
||||
ListPreference(
|
||||
key = "revanced_header_logo",
|
||||
entriesKey = "revanced_header_logo_custom_entries",
|
||||
entryValuesKey = "revanced_header_logo_custom_entry_values",
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
logoResourceNames.forEach { logo ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
"drawable",
|
||||
logo + "_" + variant + ".xml",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy custom template. Images are only used if settings
|
||||
// are imported and a custom header is enabled.
|
||||
targetResourceDirectoryNames.keys.forEach { dpi ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
dpi,
|
||||
resources = customHeaderResourceFileNames,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
applyBlock()
|
||||
|
||||
// Copy user provided images last, so if an exception is thrown due to bad input.
|
||||
if (custom != null) {
|
||||
val customFile = File(custom!!.trim())
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException(
|
||||
"The custom header path cannot be found: " +
|
||||
customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException(
|
||||
"The custom header path must be a folder: " +
|
||||
customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
customFile.listFiles { file ->
|
||||
file.isDirectory && file.name in targetResourceDirectoryNames
|
||||
}!!.forEach { dpiSourceFolder ->
|
||||
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name)
|
||||
if (!targetDpiFolder.exists()) {
|
||||
// Should never happen.
|
||||
throw IllegalStateException("Resource not found: $dpiSourceFolder")
|
||||
}
|
||||
|
||||
val customFiles = dpiSourceFolder.listFiles { file ->
|
||||
file.isFile && file.name in customHeaderResourceFileNames
|
||||
}!!
|
||||
|
||||
if (customFiles.isNotEmpty() && customFiles.size != variants.size) {
|
||||
throw PatchException(
|
||||
"Both light/dark mode images " +
|
||||
"must be specified but only found: " + customFiles.map { it.name },
|
||||
)
|
||||
}
|
||||
|
||||
customFiles.forEach { imgSourceFile ->
|
||||
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
|
||||
imgSourceFile.copyTo(target = imgTargetFile, overwrite = true)
|
||||
|
||||
copiedFiles = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException(
|
||||
"Expected to find directories and files: " +
|
||||
customHeaderResourceFileNames.contentToString() +
|
||||
"\nBut none were found in the provided option file path: " + customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,27 +3,26 @@ package app.revanced.patches.youtube.layout.branding.header
|
|||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patcher.util.Document
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.layout.branding.addBrandLicensePatch
|
||||
import app.revanced.patches.shared.layout.branding.header.CUSTOM_HEADER_RESOURCE_NAME
|
||||
import app.revanced.patches.shared.layout.branding.header.changeHeaderPatch
|
||||
import app.revanced.patches.shared.layout.branding.header.variants
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceType
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.util.copyResources
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.forEachInstructionAsSequence
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import java.io.File
|
||||
|
||||
private val variants = arrayOf("light", "dark")
|
||||
internal val variants = arrayOf("light", "dark")
|
||||
|
||||
private val logoResourceNames = arrayOf(
|
||||
"revanced_header_minimal",
|
||||
"revanced_header_rounded",
|
||||
)
|
||||
|
||||
private val targetResourceDirectoryNames = mapOf(
|
||||
"drawable-hdpi" to "194x72 px",
|
||||
|
|
@ -32,25 +31,6 @@ private val targetResourceDirectoryNames = mapOf(
|
|||
"drawable-xxxhdpi" to "512x192 px",
|
||||
)
|
||||
|
||||
/**
|
||||
* Header logos built into this patch.
|
||||
*/
|
||||
private val logoResourceNames = arrayOf(
|
||||
"revanced_header_minimal",
|
||||
"revanced_header_rounded",
|
||||
)
|
||||
|
||||
/**
|
||||
* Custom header resource/file name.
|
||||
*/
|
||||
private const val CUSTOM_HEADER_RESOURCE_NAME = "revanced_header_custom"
|
||||
|
||||
/**
|
||||
* Custom header resource/file names.
|
||||
*/
|
||||
private val customHeaderResourceFileNames = variants.map { variant ->
|
||||
"${CUSTOM_HEADER_RESOURCE_NAME}_$variant.png"
|
||||
}.toTypedArray()
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;"
|
||||
|
|
@ -97,182 +77,61 @@ private val changeHeaderBytecodePatch = bytecodePatch {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
val changeHeaderPatch = resourcePatch(
|
||||
name = "Change header",
|
||||
description = "Adds an option to change the header logo in the top left corner of the app.",
|
||||
) {
|
||||
dependsOn(addResourcesPatch, changeHeaderBytecodePatch)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
val changeHeaderPatch = changeHeaderPatch(
|
||||
targetResourceDirectoryNames = targetResourceDirectoryNames,
|
||||
changeHeaderBytecodePatch = changeHeaderBytecodePatch,
|
||||
compatiblePackages = arrayOf(
|
||||
"com.google.android.youtube" to setOf(
|
||||
"20.14.43",
|
||||
"20.21.37",
|
||||
"20.26.46",
|
||||
"20.31.42",
|
||||
"20.37.48",
|
||||
"20.40.45"
|
||||
),
|
||||
)
|
||||
|
||||
val custom by stringOption(
|
||||
name = "Custom header logo",
|
||||
description = """
|
||||
Folder with images to use as a custom header logo.
|
||||
|
||||
The folder must contain one or more of the following folders, depending on the DPI of the device:
|
||||
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
|
||||
|
||||
Each of the folders must contain all of the following files:
|
||||
${customHeaderResourceFileNames.joinToString("\n")}
|
||||
|
||||
The image dimensions must be as follows:
|
||||
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
|
||||
""".trimIndentMultiline(),
|
||||
)
|
||||
|
||||
apply {
|
||||
addResources("youtube", "layout.branding.changeHeaderPatch")
|
||||
|
||||
PreferenceScreen.GENERAL.addPreferences(
|
||||
if (custom == null) {
|
||||
ListPreference("revanced_header_logo")
|
||||
} else {
|
||||
ListPreference(
|
||||
key = "revanced_header_logo",
|
||||
entriesKey = "revanced_header_logo_custom_entries",
|
||||
entryValuesKey = "revanced_header_logo_custom_entry_values",
|
||||
)
|
||||
},
|
||||
)
|
||||
),
|
||||
variants = variants,
|
||||
logoResourceNames = logoResourceNames,
|
||||
preferenceScreen = PreferenceScreen.GENERAL,
|
||||
resourcesAppId = "youtube",
|
||||
) {
|
||||
// Logo is replaced using an attribute reference.
|
||||
document("res/values/attrs.xml").use { document ->
|
||||
val resources = document.childNodes.item(0)
|
||||
|
||||
logoResourceNames.forEach { logo ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
"drawable",
|
||||
logo + "_" + variant + ".xml",
|
||||
),
|
||||
)
|
||||
}
|
||||
fun addAttributeReference(logoName: String) {
|
||||
val item = document.createElement("attr")
|
||||
item.setAttribute("format", "reference")
|
||||
item.setAttribute("name", logoName)
|
||||
resources.appendChild(item)
|
||||
}
|
||||
|
||||
// Copy custom template. Images are only used if settings
|
||||
// are imported and a custom header is enabled.
|
||||
targetResourceDirectoryNames.keys.forEach { dpi ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
dpi,
|
||||
*customHeaderResourceFileNames,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
logoResourceNames.forEach { logoName -> addAttributeReference(logoName) }
|
||||
|
||||
// Logo is replaced using an attribute reference.
|
||||
document("res/values/attrs.xml").use { document ->
|
||||
val resources = document.childNodes.item(0)
|
||||
addAttributeReference(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
}
|
||||
|
||||
fun addAttributeReference(logoName: String) {
|
||||
val item = document.createElement("attr")
|
||||
item.setAttribute("format", "reference")
|
||||
// Add custom drawables to all styles that use the regular and premium logo.
|
||||
document("res/values/styles.xml").use { document ->
|
||||
arrayOf(
|
||||
"Base.Theme.YouTube.Light" to "light",
|
||||
"Base.Theme.YouTube.Dark" to "dark",
|
||||
"CairoLightThemeRingo2Updates" to "light",
|
||||
"CairoDarkThemeRingo2Updates" to "dark",
|
||||
).forEach { (style, mode) ->
|
||||
val styleElement = document.childNodes.findElementByAttributeValueOrThrow("name", style)
|
||||
|
||||
fun addDrawableElement(document: Document, logoName: String, mode: String) {
|
||||
val item = document.createElement("item")
|
||||
item.setAttribute("name", logoName)
|
||||
resources.appendChild(item)
|
||||
item.textContent = "@drawable/${logoName}_$mode"
|
||||
styleElement.appendChild(item)
|
||||
}
|
||||
|
||||
logoResourceNames.forEach { logoName ->
|
||||
addAttributeReference(logoName)
|
||||
}
|
||||
logoResourceNames.forEach { logoName -> addDrawableElement(document, logoName, mode) }
|
||||
|
||||
addAttributeReference(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
}
|
||||
|
||||
// Add custom drawables to all styles that use the regular and premium logo.
|
||||
document("res/values/styles.xml").use { document ->
|
||||
arrayOf(
|
||||
"Base.Theme.YouTube.Light" to "light",
|
||||
"Base.Theme.YouTube.Dark" to "dark",
|
||||
"CairoLightThemeRingo2Updates" to "light",
|
||||
"CairoDarkThemeRingo2Updates" to "dark",
|
||||
).forEach { (style, mode) ->
|
||||
val styleElement = document.childNodes.findElementByAttributeValueOrThrow(
|
||||
"name",
|
||||
style,
|
||||
)
|
||||
|
||||
fun addDrawableElement(document: Document, logoName: String, mode: String) {
|
||||
val item = document.createElement("item")
|
||||
item.setAttribute("name", logoName)
|
||||
item.textContent = "@drawable/${logoName}_$mode"
|
||||
styleElement.appendChild(item)
|
||||
}
|
||||
|
||||
logoResourceNames.forEach { logoName ->
|
||||
addDrawableElement(document, logoName, mode)
|
||||
}
|
||||
|
||||
addDrawableElement(document, CUSTOM_HEADER_RESOURCE_NAME, mode)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy user provided images last, so if an exception is thrown due to bad input.
|
||||
if (custom != null) {
|
||||
val customFile = File(custom!!.trim())
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException(
|
||||
"The custom header path cannot be found: " +
|
||||
customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException(
|
||||
"The custom header path must be a folder: " +
|
||||
customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
customFile.listFiles { file ->
|
||||
file.isDirectory && file.name in targetResourceDirectoryNames
|
||||
}!!.forEach { dpiSourceFolder ->
|
||||
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name)
|
||||
if (!targetDpiFolder.exists()) {
|
||||
// Should never happen.
|
||||
throw IllegalStateException("Resource not found: $dpiSourceFolder")
|
||||
}
|
||||
|
||||
val customFiles = dpiSourceFolder.listFiles { file ->
|
||||
file.isFile && file.name in customHeaderResourceFileNames
|
||||
}!!
|
||||
|
||||
if (customFiles.isNotEmpty() && customFiles.size != variants.size) {
|
||||
throw PatchException(
|
||||
"Both light/dark mode images " +
|
||||
"must be specified but only found: " + customFiles.map { it.name },
|
||||
)
|
||||
}
|
||||
|
||||
customFiles.forEach { imgSourceFile ->
|
||||
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
|
||||
imgSourceFile.copyTo(target = imgTargetFile, overwrite = true)
|
||||
|
||||
copiedFiles = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException(
|
||||
"Expected to find directories and files: " +
|
||||
customHeaderResourceFileNames.contentToString() +
|
||||
"\nBut none were found in the provided option file path: " + customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
addDrawableElement(document, CUSTOM_HEADER_RESOURCE_NAME, mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -188,6 +188,26 @@
|
|||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.header.changeHeaderPatch">
|
||||
<string-array name="revanced_header_logo_entries">
|
||||
<item>@string/revanced_header_logo_entry_1</item>
|
||||
<item>@string/revanced_header_logo_entry_2</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_header_logo_entry_values">
|
||||
<item>DEFAULT</item>
|
||||
<item>REGULAR</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_header_logo_custom_entries">
|
||||
<item>@string/revanced_header_logo_entry_1</item>
|
||||
<item>@string/revanced_header_logo_entry_2</item>
|
||||
<item>@string/revanced_header_logo_entry_3</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_header_logo_custom_entry_values">
|
||||
<item>DEFAULT</item>
|
||||
<item>REGULAR</item>
|
||||
<item>CUSTOM</item>
|
||||
</string-array>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
<string-array name="revanced_custom_branding_name_entries">
|
||||
<!-- Original must be first. -->
|
||||
|
|
@ -427,7 +447,7 @@
|
|||
<item>MODERN_3</item>
|
||||
</string-array>
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<patch id="layout.branding.header.changeHeaderPatch">
|
||||
<string-array name="revanced_header_logo_entries">
|
||||
<item>@string/revanced_header_logo_entry_1</item>
|
||||
<item>@string/revanced_header_logo_entry_2</item>
|
||||
|
|
|
|||
|
|
@ -1568,7 +1568,7 @@ Swipe to expand or close"</string>
|
|||
<string name="revanced_custom_branding_name_entry_3" translatable="false">YT ReVanced</string>
|
||||
<string name="revanced_custom_branding_name_entry_4" translatable="false">YT</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<patch id="layout.branding.header.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Header logo</string>
|
||||
<string name="revanced_header_logo_entry_1">Default</string>
|
||||
<string name="revanced_header_logo_entry_2">Regular</string>
|
||||
|
|
@ -1801,6 +1801,12 @@ Video playback with AV1 may stutter or drop frames."</string>
|
|||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.header.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Header logo</string>
|
||||
<string name="revanced_header_logo_entry_1">Default</string>
|
||||
<string name="revanced_header_logo_entry_2" translatable="false">ReVanced</string>
|
||||
<string name="revanced_header_logo_entry_3">Custom</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_entry_2" translatable="false">YT Music ReVanced</string>
|
||||
<string name="revanced_custom_branding_name_entry_3" translatable="false">Music ReVanced</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue