mirror of
https://github.com/revanced/revanced-patches
synced 2025-01-16 04:07:31 +01:00
Init
This commit is contained in:
parent
2c65044f3a
commit
a5a14ac31a
@ -1,3 +1,7 @@
|
||||
public final class app/revanced/patches/all/layout/branding/IconPatchKt {
|
||||
public static final fun getChangeIconPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/activity/exportall/ExportAllActivitiesPatchKt {
|
||||
public static final fun getExportAllActivitiesPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
}
|
||||
|
@ -0,0 +1,137 @@
|
||||
package app.revanced.patches.all.layout.branding
|
||||
|
||||
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.patcher.util.Document
|
||||
import app.revanced.util.getNode
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
val changeIconPatch = resourcePatch(
|
||||
name = "Change icon",
|
||||
description = "Changes the app icon to a custom icon. By default, the \"ReVanced icon\" is used.",
|
||||
use = false,
|
||||
) {
|
||||
val revancedIconOptionValue = "" // Empty value == ReVanced icon.
|
||||
|
||||
val pixelDensities = setOf(
|
||||
"xxxhdpi",
|
||||
"xxhdpi",
|
||||
"xhdpi",
|
||||
"hdpi",
|
||||
"mdpi",
|
||||
)
|
||||
|
||||
val iconOptions = buildMap {
|
||||
arrayOf("foreground", "background", "monochrome").forEach { iconType ->
|
||||
this += pixelDensities.associateBy {
|
||||
stringOption(
|
||||
key = "${iconType}IconPath",
|
||||
default = revancedIconOptionValue,
|
||||
values = mapOf("ReVanced Logo" to revancedIconOptionValue),
|
||||
title = "Icon file path (Pixel density: $it, Icon type: $iconType)",
|
||||
description = "The path to the icon file to apply to the app for the pixel density $it " +
|
||||
"and icon type $iconType.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// This might confuse the user.
|
||||
put(
|
||||
"full",
|
||||
stringOption(
|
||||
key = "fullIconPath",
|
||||
default = revancedIconOptionValue,
|
||||
values = mapOf("ReVanced Logo" to revancedIconOptionValue),
|
||||
title = "Full icon file path",
|
||||
description = "The path to the icon file to apply when the app " +
|
||||
"does not have a specific icon for the pixel density.",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
execute {
|
||||
manifest {
|
||||
val applicationNode = getNode("application")
|
||||
val iconResourceReference = applicationNode.attributes.getNamedItem("android:icon").textContent!!
|
||||
|
||||
val iconResourceFiles = resolve(iconResourceReference)
|
||||
|
||||
iconResourceFiles.forEach { resourceFile ->
|
||||
if (resourceFile.extension == "xml" && resourceFile.name.startsWith("ic_launcher")) {
|
||||
val adaptiveIcon = parseAdaptiveIcon(resourceFile)
|
||||
|
||||
// TODO: Replace the background, foreground, and monochrome icons with the custom icons.
|
||||
} else {
|
||||
// TODO: Replace the icon with fullIcon.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context(ResourcePatchContext)
|
||||
fun <T> manifest(block: Document.() -> T) = document("AndroidManifest.xml").use(block)
|
||||
|
||||
context(ResourcePatchContext)
|
||||
private fun resolve(resourceReference: String): List<File> {
|
||||
val isMipmap = resourceReference.startsWith("@mipmap/")
|
||||
val isDrawable = resourceReference.startsWith("@drawable/")
|
||||
|
||||
val directories = get("res").listFiles(
|
||||
if (isMipmap) {
|
||||
FilenameFilter { _, name -> name.startsWith("mipmap-") }
|
||||
} else if (isDrawable) {
|
||||
FilenameFilter { _, name -> name.startsWith("drawable-") }
|
||||
} else {
|
||||
throw PatchException("Unsupported resource reference: $resourceReference")
|
||||
},
|
||||
)!!
|
||||
|
||||
// The name does not have an extension. It is the name of the resource.
|
||||
val resourceName = resourceReference.split("/").last()
|
||||
val resources = directories.mapNotNull {
|
||||
// Find the first file that starts with the resource name.
|
||||
it.listFiles { _, name -> name.startsWith(resourceName) }!!.firstOrNull()
|
||||
}
|
||||
|
||||
return resources
|
||||
}
|
||||
|
||||
private class IconResource(
|
||||
val file: File,
|
||||
val pixelDensity: String,
|
||||
)
|
||||
|
||||
context(ResourcePatchContext)
|
||||
private fun parseAdaptiveIcon(xmlFile: File) = document(xmlFile.absolutePath).use { adaptiveIconNode ->
|
||||
val adaptiveIcon = adaptiveIconNode.getNode("adaptive-icon")
|
||||
|
||||
fun getIconResourceReference(iconType: String): List<IconResource>? {
|
||||
val resourceReferenceString = adaptiveIcon.getNode(iconType)?.let {
|
||||
it.attributes.getNamedItem("android:drawable").textContent!!
|
||||
}
|
||||
|
||||
if (resourceReferenceString == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return resolve(resourceReferenceString).map {
|
||||
IconResource(file = it, pixelDensity = it.parentFile.name.split("-").last())
|
||||
}
|
||||
}
|
||||
|
||||
AdaptiveIcon(
|
||||
getIconResourceReference("background")!!,
|
||||
getIconResourceReference("foreground")!!,
|
||||
getIconResourceReference("monochrome"),
|
||||
)
|
||||
}
|
||||
|
||||
private class AdaptiveIcon(
|
||||
val background: List<IconResource>,
|
||||
val foreground: List<IconResource>,
|
||||
val monochrome: List<IconResource>?,
|
||||
)
|
@ -1,8 +1,8 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val constructCategoryBarFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
@ -16,7 +16,5 @@ internal val constructCategoryBarFingerprint = fingerprint {
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
)
|
||||
}
|
||||
|
@ -23,16 +23,14 @@ fun NodeList.asSequence() = (0 until this.length).asSequence().map { this.item(i
|
||||
* Returns a sequence for all child nodes.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun Node.childElementsSequence() =
|
||||
this.childNodes.asSequence().filter { it.nodeType == Node.ELEMENT_NODE } as Sequence<Element>
|
||||
fun Node.childElementsSequence() = this.childNodes.asSequence().filter { it.nodeType == Node.ELEMENT_NODE } as Sequence<Element>
|
||||
|
||||
/**
|
||||
* Performs the given [action] on each child element.
|
||||
*/
|
||||
inline fun Node.forEachChildElement(action: (Element) -> Unit) =
|
||||
childElementsSequence().forEach {
|
||||
action(it)
|
||||
}
|
||||
inline fun Node.forEachChildElement(action: (Element) -> Unit) = childElementsSequence().forEach {
|
||||
action(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverse the DOM tree starting from the given root node.
|
||||
@ -141,7 +139,8 @@ internal fun Node.addResource(
|
||||
appendChild(resource.serialize(ownerDocument, resourceCallback))
|
||||
}
|
||||
|
||||
internal fun org.w3c.dom.Document.getNode(tagName: String) = this.getElementsByTagName(tagName).item(0)
|
||||
internal fun org.w3c.dom.Document.getNode(tagName: String) = getElementsByTagName(tagName).item(0)
|
||||
internal fun Node.getNode(tagName: String) = childNodes.asSequence().find { it.nodeName == tagName }
|
||||
|
||||
internal fun NodeList.findElementByAttributeValue(attributeName: String, value: String): Element? {
|
||||
for (i in 0 until length) {
|
||||
@ -164,8 +163,7 @@ internal fun NodeList.findElementByAttributeValue(attributeName: String, value:
|
||||
return null
|
||||
}
|
||||
|
||||
internal fun NodeList.findElementByAttributeValueOrThrow(attributeName: String, value: String) =
|
||||
findElementByAttributeValue(attributeName, value) ?: throw PatchException("Could not find: $attributeName $value")
|
||||
internal fun NodeList.findElementByAttributeValueOrThrow(attributeName: String, value: String) = findElementByAttributeValue(attributeName, value) ?: throw PatchException("Could not find: $attributeName $value")
|
||||
|
||||
internal fun Element.copyAttributesFrom(oldContainer: Element) {
|
||||
// Copy attributes from the old element to the new element
|
||||
|
Loading…
x
Reference in New Issue
Block a user