fix(Patch options): some patch options in RVX Manager are marked with custom value

This commit is contained in:
inotia00 2024-06-12 21:45:05 +09:00
parent f7fe7e8caf
commit 8dc8bffea7
15 changed files with 473 additions and 432 deletions

View File

@ -9,6 +9,7 @@ import app.revanced.util.ResourceGroup
import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.copyResources import app.revanced.util.copyResources
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.underBarOrThrow
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
@ -18,13 +19,13 @@ object CustomBrandingIconPatch : BaseResourcePatch(
description = "Changes the YouTube Music app icon to the icon specified in options.json.", description = "Changes the YouTube Music app icon to the icon specified in options.json.",
compatiblePackages = COMPATIBLE_PACKAGE compatiblePackages = COMPATIBLE_PACKAGE
) { ) {
private const val DEFAULT_ICON_KEY = "Revancify Blue" private const val DEFAULT_ICON = "revancify_blue"
private val availableIcon = mapOf( private val availableIcon = mapOf(
"AFN Blue" to "afn_blue", "AFN Blue" to "afn_blue",
"AFN Red" to "afn_red", "AFN Red" to "afn_red",
"MMT" to "mmt", "MMT" to "mmt",
DEFAULT_ICON_KEY to "revancify_blue", "Revancify Blue" to DEFAULT_ICON,
"Revancify Red" to "revancify_red", "Revancify Red" to "revancify_red",
"YouTube Music" to "youtube_music" "YouTube Music" to "youtube_music"
) )
@ -93,9 +94,9 @@ object CustomBrandingIconPatch : BaseResourcePatch(
) )
} }
private val AppIcon by stringPatchOption( private val AppIcon = stringPatchOption(
key = "AppIcon", key = "AppIcon",
default = DEFAULT_ICON_KEY, default = DEFAULT_ICON,
values = availableIcon, values = availableIcon,
title = "App icon", title = "App icon",
description = """ description = """
@ -129,12 +130,15 @@ object CustomBrandingIconPatch : BaseResourcePatch(
) )
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
AppIcon?.let { appIcon ->
val appIconValue = appIcon.lowercase().replace(" ", "_") // Check patch options first.
val appIconResourcePath = "music/branding/$appIconValue" val appIcon = AppIcon
.underBarOrThrow()
val appIconResourcePath = "music/branding/$appIcon"
// Check if a custom path is used in the patch options. // Check if a custom path is used in the patch options.
if (!availableIcon.containsValue(appIconValue)) { if (!availableIcon.containsValue(appIcon)) {
launcherIconResourceGroups.let { resourceGroups -> launcherIconResourceGroups.let { resourceGroups ->
try { try {
val path = File(appIcon) val path = File(appIcon)
@ -193,6 +197,5 @@ object CustomBrandingIconPatch : BaseResourcePatch(
} }
} }
} }
} ?: throw PatchException("Invalid app icon path.")
} }
} }

View File

@ -1,11 +1,11 @@
package app.revanced.patches.music.layout.branding.name package app.revanced.patches.music.layout.branding.name
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
@Suppress("DEPRECATION", "unused") @Suppress("DEPRECATION", "unused")
object CustomBrandingNamePatch : BaseResourcePatch( object CustomBrandingNamePatch : BaseResourcePatch(
@ -16,7 +16,7 @@ object CustomBrandingNamePatch : BaseResourcePatch(
private const val APP_NAME_NOTIFICATION = "ReVanced Extended Music" private const val APP_NAME_NOTIFICATION = "ReVanced Extended Music"
private const val APP_NAME_LAUNCHER = "RVX Music" private const val APP_NAME_LAUNCHER = "RVX Music"
private val AppNameNotification by stringPatchOption( private val AppNameNotification = stringPatchOption(
key = "AppNameNotification", key = "AppNameNotification",
default = APP_NAME_LAUNCHER, default = APP_NAME_LAUNCHER,
values = mapOf( values = mapOf(
@ -30,7 +30,7 @@ object CustomBrandingNamePatch : BaseResourcePatch(
required = true required = true
) )
private val AppNameLauncher by stringPatchOption( private val AppNameLauncher = stringPatchOption(
key = "AppNameLauncher", key = "AppNameLauncher",
default = APP_NAME_LAUNCHER, default = APP_NAME_LAUNCHER,
values = mapOf( values = mapOf(
@ -46,12 +46,16 @@ object CustomBrandingNamePatch : BaseResourcePatch(
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// Check patch options first.
val notificationName = AppNameNotification
.valueOrThrow()
val launcherName = AppNameLauncher
.valueOrThrow()
context.removeStringsElements( context.removeStringsElements(
arrayOf("app_launcher_name", "app_name") arrayOf("app_launcher_name", "app_name")
) )
AppNameNotification?.let { notificationName ->
AppNameLauncher?.let { launcherName ->
context.xmlEditor["res/values/strings.xml"].use { editor -> context.xmlEditor["res/values/strings.xml"].use { editor ->
val document = editor.file val document = editor.file
@ -68,7 +72,5 @@ object CustomBrandingNamePatch : BaseResourcePatch(
.appendChild(stringElement) .appendChild(stringElement)
} }
} }
} ?: throw PatchException("Invalid launcher name.")
} ?: throw PatchException("Invalid notification name.")
} }
} }

View File

@ -12,6 +12,7 @@ import app.revanced.patches.music.utils.settings.ResourceUtils.sortPreferenceCat
import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements
import app.revanced.util.copyXmlNode import app.revanced.util.copyXmlNode
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
import org.w3c.dom.Element import org.w3c.dom.Element
import java.io.Closeable import java.io.Closeable
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -30,7 +31,7 @@ object SettingsPatch : BaseResourcePatch(
), Closeable { ), Closeable {
private const val DEFAULT_NAME = "ReVanced Extended" private const val DEFAULT_NAME = "ReVanced Extended"
private val RVXSettingsMenuName by stringPatchOption( private val RVXSettingsMenuName = stringPatchOption(
key = "RVXSettingsMenuName", key = "RVXSettingsMenuName",
default = DEFAULT_NAME, default = DEFAULT_NAME,
title = "RVX settings menu name", title = "RVX settings menu name",
@ -38,12 +39,20 @@ object SettingsPatch : BaseResourcePatch(
required = true required = true
) )
private lateinit var customName: String
lateinit var contexts: ResourceContext lateinit var contexts: ResourceContext
internal var upward0636 = false internal var upward0636 = false
internal var upward0642 = false internal var upward0642 = false
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
/**
* check patch options
*/
customName = RVXSettingsMenuName
.valueOrThrow()
/** /**
* set resource context * set resource context
*/ */
@ -193,7 +202,6 @@ object SettingsPatch : BaseResourcePatch(
* change RVX settings menu name * change RVX settings menu name
* since it must be invoked after the Translations patch, it must be the last in the order. * since it must be invoked after the Translations patch, it must be the last in the order.
*/ */
RVXSettingsMenuName?.let { customName ->
if (customName != DEFAULT_NAME) { if (customName != DEFAULT_NAME) {
contexts.removeStringsElements( contexts.removeStringsElements(
arrayOf("revanced_extended_settings_title") arrayOf("revanced_extended_settings_title")
@ -214,14 +222,18 @@ object SettingsPatch : BaseResourcePatch(
} }
} }
} }
} ?: println("WARNING: Invalid RVX settings menu name. RVX settings menu name does not change.")
/**
* add import export settings
*/
addPreferenceWithIntent( addPreferenceWithIntent(
CategoryType.MISC, CategoryType.MISC,
"revanced_extended_settings_import_export" "revanced_extended_settings_import_export"
) )
/**
* sort preference
*/
CategoryType.entries.sorted().forEach { CategoryType.entries.sorted().forEach {
contexts.sortPreferenceCategory(it.value) contexts.sortPreferenceCategory(it.value)
} }

View File

@ -4,6 +4,7 @@ import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
import java.io.FileWriter import java.io.FileWriter
import java.nio.file.Files import java.nio.file.Files
@ -17,7 +18,7 @@ object CustomBrandingNamePatch : BaseResourcePatch(
private const val ORIGINAL_APP_NAME = "Reddit" private const val ORIGINAL_APP_NAME = "Reddit"
private const val APP_NAME = "RVX Reddit" private const val APP_NAME = "RVX Reddit"
private val AppName by stringPatchOption( private val AppName = stringPatchOption(
key = "AppName", key = "AppName",
default = ORIGINAL_APP_NAME, default = ORIGINAL_APP_NAME,
values = mapOf( values = mapOf(
@ -30,14 +31,14 @@ object CustomBrandingNamePatch : BaseResourcePatch(
) )
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
val appName = if (AppName != null) { val appName = AppName
AppName!! .valueOrThrow()
} else {
println("WARNING: Invalid app name. Does not apply patches.") if (appName == ORIGINAL_APP_NAME) {
ORIGINAL_APP_NAME println("INFO: App name will remain unchanged as it matches the original.")
return
} }
if (appName != ORIGINAL_APP_NAME) {
val resDirectory = context["res"] val resDirectory = context["res"]
val valuesV24Directory = resDirectory.resolve("values-v24") val valuesV24Directory = resDirectory.resolve("values-v24")
@ -66,8 +67,5 @@ object CustomBrandingNamePatch : BaseResourcePatch(
document.getElementsByTagName("resources").item(0).appendChild(stringElement) document.getElementsByTagName("resources").item(0).appendChild(stringElement)
} }
} }
} else {
println("INFO: App name will remain unchanged as it matches the original.")
}
} }
} }

View File

@ -4,6 +4,7 @@ import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
import org.w3c.dom.Element import org.w3c.dom.Element
import java.io.Closeable import java.io.Closeable
@ -21,7 +22,7 @@ object ChangePackageNamePatch : BaseResourcePatch(
private lateinit var context: ResourceContext private lateinit var context: ResourceContext
private var redditPackageName = PACKAGE_NAME_REDDIT private var redditPackageName = PACKAGE_NAME_REDDIT
private val PackageNameReddit by stringPatchOption( private val PackageNameReddit = stringPatchOption(
key = "PackageNameReddit", key = "PackageNameReddit",
default = PACKAGE_NAME_REDDIT, default = PACKAGE_NAME_REDDIT,
values = mapOf( values = mapOf(
@ -37,13 +38,14 @@ object ChangePackageNamePatch : BaseResourcePatch(
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
this.context = context this.context = context
if (PackageNameReddit != null) { redditPackageName = PackageNameReddit
redditPackageName = PackageNameReddit!! .valueOrThrow()
} else {
println("WARNING: Invalid package name. Does not apply patches.") if (redditPackageName == PACKAGE_NAME_REDDIT) {
println("INFO: Package name will remain unchanged as it matches the original.")
return
} }
if (redditPackageName != PACKAGE_NAME_REDDIT) {
// Ensure device runs Android. // Ensure device runs Android.
try { try {
// RVX Manager // RVX Manager
@ -51,13 +53,11 @@ object ChangePackageNamePatch : BaseResourcePatch(
// For some reason, in Android AAPT2, a compilation error occurs when changing the [strings.xml] of the Reddit // For some reason, in Android AAPT2, a compilation error occurs when changing the [strings.xml] of the Reddit
// This only affects RVX Manager, and has not yet found a valid workaround // This only affects RVX Manager, and has not yet found a valid workaround
Class.forName("android.os.Environment") Class.forName("android.os.Environment")
return
} catch (_: ClassNotFoundException) { } catch (_: ClassNotFoundException) {
// CLI // CLI
context.replacePackageName(redditPackageName) context.replacePackageName(redditPackageName)
} }
} else {
println("INFO: Package name will remain unchanged as it matches the original.")
}
} }
override fun close() { override fun close() {

View File

@ -6,6 +6,7 @@ import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatc
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.reddit.utils.integrations.IntegrationsPatch import app.revanced.patches.reddit.utils.integrations.IntegrationsPatch
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
import kotlin.io.path.exists import kotlin.io.path.exists
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@ -21,7 +22,7 @@ object SettingsPatch : BaseResourcePatch(
) { ) {
private const val DEFAULT_NAME = "ReVanced Extended" private const val DEFAULT_NAME = "ReVanced Extended"
private val RVXSettingsMenuName by stringPatchOption( private val RVXSettingsMenuName = stringPatchOption(
key = "RVXSettingsMenuName", key = "RVXSettingsMenuName",
default = DEFAULT_NAME, default = DEFAULT_NAME,
title = "RVX settings menu name", title = "RVX settings menu name",
@ -32,11 +33,8 @@ object SettingsPatch : BaseResourcePatch(
/** /**
* Replace settings icon and label * Replace settings icon and label
*/ */
val settingsLabel = RVXSettingsMenuName
var settingsLabel = DEFAULT_NAME .valueOrThrow()
if (!RVXSettingsMenuName.isNullOrEmpty())
settingsLabel = RVXSettingsMenuName!!
arrayOf("preferences", "preferences_logged_in").forEach { targetXML -> arrayOf("preferences", "preferences_logged_in").forEach { targetXML ->
val resDirectory = context["res"] val resDirectory = context["res"]

View File

@ -1,12 +1,12 @@
package app.revanced.patches.youtube.layout.actionbuttons package app.revanced.patches.youtube.layout.actionbuttons
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources import app.revanced.util.copyResources
import app.revanced.util.lowerCaseOrThrow
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
@Suppress("unused") @Suppress("unused")
@ -16,15 +16,15 @@ object ShortsActionButtonsPatch : BaseResourcePatch(
dependencies = setOf(SettingsPatch::class), dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE compatiblePackages = COMPATIBLE_PACKAGE
) { ) {
private const val DEFAULT_ICON_KEY = "Round" private const val DEFAULT_ICON = "round"
private val IconType by stringPatchOption( private val IconType = stringPatchOption(
key = "IconType", key = "IconType",
default = DEFAULT_ICON_KEY, default = DEFAULT_ICON,
values = mapOf( values = mapOf(
"Outline" to "outline", "Outline" to "outline",
"OutlineCircle" to "outlinecircle", "OutlineCircle" to "outlinecircle",
DEFAULT_ICON_KEY to "round" "Round" to DEFAULT_ICON
), ),
title = "Shorts icon style ", title = "Shorts icon style ",
description = "The style of the icons for the action buttons in the Shorts player.", description = "The style of the icons for the action buttons in the Shorts player.",
@ -32,8 +32,10 @@ object ShortsActionButtonsPatch : BaseResourcePatch(
) )
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
IconType?.let { iconType ->
val selectedIconType = iconType.lowercase() // Check patch options first.
val iconType = IconType
.lowerCaseOrThrow()
arrayOf( arrayOf(
"xxxhdpi", "xxxhdpi",
@ -43,7 +45,7 @@ object ShortsActionButtonsPatch : BaseResourcePatch(
"mdpi" "mdpi"
).forEach { dpi -> ).forEach { dpi ->
context.copyResources( context.copyResources(
"youtube/shorts/actionbuttons/$selectedIconType", "youtube/shorts/actionbuttons/$iconType",
ResourceGroup( ResourceGroup(
"drawable-$dpi", "drawable-$dpi",
"ic_remix_filled_white_shadowed.webp", "ic_remix_filled_white_shadowed.webp",
@ -67,6 +69,7 @@ object ShortsActionButtonsPatch : BaseResourcePatch(
"ic_right_share_32c.xml" "ic_right_share_32c.xml"
) )
) )
}
context.copyResources( context.copyResources(
"youtube/shorts/actionbuttons/shared", "youtube/shorts/actionbuttons/shared",
@ -77,8 +80,6 @@ object ShortsActionButtonsPatch : BaseResourcePatch(
"reel_search_bold_24dp.xml" "reel_search_bold_24dp.xml"
) )
) )
}
} ?: throw PatchException("Invalid icon type.")
SettingsPatch.updatePatchStatus(this) SettingsPatch.updatePatchStatus(this)
} }

View File

@ -1,7 +1,6 @@
package app.revanced.patches.youtube.layout.branding.icon package app.revanced.patches.youtube.layout.branding.icon
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
@ -9,26 +8,26 @@ import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStat
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup import app.revanced.util.ResourceGroup
import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.copyFile
import app.revanced.util.copyResources import app.revanced.util.copyResources
import app.revanced.util.copyXmlNode import app.revanced.util.copyXmlNode
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import java.io.File import app.revanced.util.underBarOrThrow
import java.nio.file.Files
@Suppress("DEPRECATION", "unused") @Suppress("unused")
object CustomBrandingIconPatch : BaseResourcePatch( object CustomBrandingIconPatch : BaseResourcePatch(
name = "Custom branding icon YouTube", name = "Custom branding icon YouTube",
description = "Changes the YouTube app icon to the icon specified in options.json.", description = "Changes the YouTube app icon to the icon specified in options.json.",
dependencies = setOf(SettingsPatch::class), dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
) { ) {
private const val DEFAULT_ICON_KEY = "Revancify Blue" private const val DEFAULT_ICON = "revancify_blue"
private val availableIcon = mapOf( private val availableIcon = mapOf(
"AFN Blue" to "afn_blue", "AFN Blue" to "afn_blue",
"AFN Red" to "afn_red", "AFN Red" to "afn_red",
"MMT" to "mmt", "MMT" to "mmt",
DEFAULT_ICON_KEY to "revancify_blue", "Revancify Blue" to DEFAULT_ICON,
"Revancify Red" to "revancify_red", "Revancify Red" to "revancify_red",
"YouTube" to "youtube" "YouTube" to "youtube"
) )
@ -109,9 +108,9 @@ object CustomBrandingIconPatch : BaseResourcePatch(
// region patch option // region patch option
val AppIcon by stringPatchOption( val AppIcon = stringPatchOption(
key = "AppIcon", key = "AppIcon",
default = DEFAULT_ICON_KEY, default = DEFAULT_ICON,
values = availableIcon, values = availableIcon,
title = "App icon", title = "App icon",
description = """ description = """
@ -176,13 +175,16 @@ object CustomBrandingIconPatch : BaseResourcePatch(
// endregion // endregion
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
AppIcon?.let { appIcon ->
val appIconValue = appIcon.lowercase().replace(" ", "_") // Check patch options first.
val appIconResourcePath = "youtube/branding/$appIconValue" val appIcon = AppIcon
.underBarOrThrow()
val appIconResourcePath = "youtube/branding/$appIcon"
val stockResourcePath = "youtube/branding/stock" val stockResourcePath = "youtube/branding/stock"
// Check if a custom path is used in the patch options. // Check if a custom path is used in the patch options.
if (!availableIcon.containsValue(appIconValue)) { if (!availableIcon.containsValue(appIcon)) {
val copiedFiles = context.copyFile( val copiedFiles = context.copyFile(
launcherIconResourceGroups, launcherIconResourceGroups,
appIcon, appIcon,
@ -250,38 +252,7 @@ object CustomBrandingIconPatch : BaseResourcePatch(
context.copyXmlNode("$stockResourcePath/splash", "values-v31/styles.xml", "resources") context.copyXmlNode("$stockResourcePath/splash", "values-v31/styles.xml", "resources")
} }
context.updatePatchStatusIcon(appIconValue) context.updatePatchStatusIcon(appIcon)
}
} ?: throw PatchException("Invalid app icon path.")
}
private fun ResourceContext.copyFile(
iconResourceGroup: List<ResourceGroup>,
path: String,
message: String
): Boolean {
iconResourceGroup.let { resourceGroups ->
try {
val filePath = File(path)
val resourceDirectory = this["res"]
resourceGroups.forEach { group ->
val fromDirectory = filePath.resolve(group.resourceDirectoryName)
val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName)
group.resources.forEach { iconFileName ->
Files.write(
toDirectory.resolve(iconFileName).toPath(),
fromDirectory.resolve(iconFileName).readBytes()
)
} }
} }
return true
} catch (_: Exception) {
println(message)
}
}
return false
}
} }

View File

@ -1,13 +1,13 @@
package app.revanced.patches.youtube.layout.branding.name package app.revanced.patches.youtube.layout.branding.name
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusLabel import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusLabel
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
@Suppress("DEPRECATION", "unused") @Suppress("DEPRECATION", "unused")
object CustomBrandingNamePatch : BaseResourcePatch( object CustomBrandingNamePatch : BaseResourcePatch(
@ -18,7 +18,7 @@ object CustomBrandingNamePatch : BaseResourcePatch(
) { ) {
private const val APP_NAME = "RVX" private const val APP_NAME = "RVX"
private val AppName by stringPatchOption( private val AppName = stringPatchOption(
key = "AppName", key = "AppName",
default = APP_NAME, default = APP_NAME,
values = mapOf( values = mapOf(
@ -33,16 +33,20 @@ object CustomBrandingNamePatch : BaseResourcePatch(
) )
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// Check patch options first.
val appName = AppName
.valueOrThrow()
context.removeStringsElements( context.removeStringsElements(
arrayOf("application_name") arrayOf("application_name")
) )
AppName?.let {
context.xmlEditor["res/values/strings.xml"].use { editor -> context.xmlEditor["res/values/strings.xml"].use { editor ->
val document = editor.file val document = editor.file
mapOf( mapOf(
"application_name" to it "application_name" to appName
).forEach { (k, v) -> ).forEach { (k, v) ->
val stringElement = document.createElement("string") val stringElement = document.createElement("string")
@ -52,7 +56,6 @@ object CustomBrandingNamePatch : BaseResourcePatch(
document.getElementsByTagName("resources").item(0).appendChild(stringElement) document.getElementsByTagName("resources").item(0).appendChild(stringElement)
} }
} }
context.updatePatchStatusLabel(it) context.updatePatchStatusLabel(appName)
} ?: throw PatchException("Invalid app name.")
} }
} }

View File

@ -27,6 +27,15 @@ object DoubleTapLengthPatch : BaseResourcePatch(
) )
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// Check patch options first.
val splits = DoubleTapLengthArrays
?.replace(" ", "")
?.split(",")
?: throw PatchException("Invalid double-tap length array.")
if (splits.isEmpty()) throw IllegalArgumentException("Invalid double-tap length elements")
val lengthElements = splits.map { it }
val arrayPath = "res/values-v21/arrays.xml" val arrayPath = "res/values-v21/arrays.xml"
val entriesName = "double_tap_length_entries" val entriesName = "double_tap_length_entries"
val entryValueName = "double_tap_length_values" val entryValueName = "double_tap_length_values"
@ -46,12 +55,6 @@ object DoubleTapLengthPatch : BaseResourcePatch(
) )
) )
val length = DoubleTapLengthArrays
?: throw PatchException("Invalid double-tap length array.")
val splits = length.replace(" ", "").split(",")
if (splits.isEmpty()) throw IllegalArgumentException("Invalid double-tap length elements")
val lengthElements = splits.map { it }
for (index in 0 until splits.count()) { for (index in 0 until splits.count()) {
context.addEntryValues(arrayPath, lengthElements[index], entryValueName) context.addEntryValues(arrayPath, lengthElements[index], entryValueName)
context.addEntryValues(arrayPath, lengthElements[index], entriesName) context.addEntryValues(arrayPath, lengthElements[index], entriesName)

View File

@ -1,13 +1,13 @@
package app.revanced.patches.youtube.layout.theme package app.revanced.patches.youtube.layout.theme
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.youtube.layout.theme.BaseThemePatch.isMonetPatchIncluded import app.revanced.patches.youtube.layout.theme.BaseThemePatch.isMonetPatchIncluded
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusTheme import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusTheme
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
import org.w3c.dom.Element import org.w3c.dom.Element
@Suppress("DEPRECATION", "unused") @Suppress("DEPRECATION", "unused")
@ -38,7 +38,7 @@ object ThemePatch : BaseResourcePatch(
private const val LIGHT_ORANGE_COLOR = "#FFFFE6CC" private const val LIGHT_ORANGE_COLOR = "#FFFFE6CC"
private const val LIGHT_RED_COLOR = "#FFFFD6D6" private const val LIGHT_RED_COLOR = "#FFFFD6D6"
private val DarkThemeBackgroundColor by stringPatchOption( private val DarkThemeBackgroundColor = stringPatchOption(
key = "DarkThemeBackgroundColor", key = "DarkThemeBackgroundColor",
default = AMOLED_BLACK_COLOR, default = AMOLED_BLACK_COLOR,
values = mapOf( values = mapOf(
@ -56,7 +56,7 @@ object ThemePatch : BaseResourcePatch(
required = true required = true
) )
private val LightThemeBackgroundColor by stringPatchOption( private val LightThemeBackgroundColor = stringPatchOption(
key = "LightThemeBackgroundColor", key = "LightThemeBackgroundColor",
default = WHITE_COLOR, default = WHITE_COLOR,
values = mapOf( values = mapOf(
@ -111,11 +111,12 @@ object ThemePatch : BaseResourcePatch(
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// Check patch options first.
val darkThemeColor = DarkThemeBackgroundColor val darkThemeColor = DarkThemeBackgroundColor
?: throw PatchException("Invalid dark color.") .valueOrThrow()
val lightThemeColor = LightThemeBackgroundColor val lightThemeColor = LightThemeBackgroundColor
?: throw PatchException("Invalid light color.") .valueOrThrow()
arrayOf("values", "values-v31").forEach { path -> arrayOf("values", "values-v31").forEach { path ->
context.xmlEditor["res/$path/colors.xml"].use { editor -> context.xmlEditor["res/$path/colors.xml"].use { editor ->

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.visual package app.revanced.patches.youtube.layout.visual
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.youtube.layout.branding.icon.CustomBrandingIconPatch import app.revanced.patches.youtube.layout.branding.icon.CustomBrandingIconPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
@ -9,6 +10,7 @@ import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources import app.revanced.util.copyResources
import app.revanced.util.doRecursively import app.revanced.util.doRecursively
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.underBarOrThrow
import org.w3c.dom.Element import org.w3c.dom.Element
@Suppress("DEPRECATION", "unused") @Suppress("DEPRECATION", "unused")
@ -19,14 +21,14 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
use = false use = false
) { ) {
private const val DEFAULT_ICON_KEY = "Extension" private const val DEFAULT_ICON = "extension"
private val RVXSettingsMenuIcon by stringPatchOption( private val RVXSettingsMenuIcon = stringPatchOption(
key = "RVXSettingsMenuIcon", key = "RVXSettingsMenuIcon",
default = DEFAULT_ICON_KEY, default = DEFAULT_ICON,
values = mapOf( values = mapOf(
"Custom branding icon" to "custom_branding_icon", "Custom branding icon" to "custom_branding_icon",
DEFAULT_ICON_KEY to "extension", "Extension" to DEFAULT_ICON,
"Gear" to "gear", "Gear" to "gear",
"ReVanced" to "revanced", "ReVanced" to "revanced",
"ReVanced Colored" to "revanced_colored", "ReVanced Colored" to "revanced_colored",
@ -38,6 +40,13 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// Check patch options first.
val selectedIconType = RVXSettingsMenuIcon
.underBarOrThrow()
val customBrandingIconType = CustomBrandingIconPatch.AppIcon
.underBarOrThrow()
// region copy shared resources. // region copy shared resources.
arrayOf( arrayOf(
@ -57,11 +66,9 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
// region copy RVX settings menu icon. // region copy RVX settings menu icon.
RVXSettingsMenuIcon?.lowercase()?.replace(" ", "_")?.let { selectedIconType ->
CustomBrandingIconPatch.AppIcon?.lowercase()?.replace(" ", "_")?.let { appIconValue ->
val fallbackIconPath = "youtube/visual/icons/extension" val fallbackIconPath = "youtube/visual/icons/extension"
val iconPath = when (selectedIconType) { val iconPath = when (selectedIconType) {
"custom_branding_icon" -> "youtube/branding/$appIconValue/settings" "custom_branding_icon" -> "youtube/branding/$customBrandingIconType/settings"
else -> "youtube/visual/icons/$selectedIconType" else -> "youtube/visual/icons/$selectedIconType"
} }
val resourceGroup = ResourceGroup( val resourceGroup = ResourceGroup(
@ -81,8 +88,6 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
// and will raise an error without fallback icon // and will raise an error without fallback icon
context.copyResources(fallbackIconPath, resourceGroup) context.copyResources(fallbackIconPath, resourceGroup)
} }
}
}
// endregion. // endregion.

View File

@ -12,6 +12,7 @@ import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources import app.revanced.util.copyResources
import app.revanced.util.copyXmlNode import app.revanced.util.copyXmlNode
import app.revanced.util.doRecursively import app.revanced.util.doRecursively
import app.revanced.util.lowerCaseOrThrow
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import org.w3c.dom.Element import org.w3c.dom.Element
@ -37,27 +38,24 @@ object OverlayButtonsPatch : BaseResourcePatch(
private const val DEFAULT_MARGIN = "0.0dip" private const val DEFAULT_MARGIN = "0.0dip"
private const val WIDER_MARGIN = "6.0dip" private const val WIDER_MARGIN = "6.0dip"
private const val DEFAULT_ICON_KEY = "Bold" private const val DEFAULT_ICON = "bold"
// Mapping of icon types to their respective resource folder names
private val iconTypes = mapOf(
DEFAULT_ICON_KEY to "bold",
"Rounded" to "rounded",
"Thin" to "thin"
)
// Option to select icon type // Option to select icon type
private val IconType by stringPatchOption( private val IconType = stringPatchOption(
key = "IconType", key = "IconType",
default = DEFAULT_ICON_KEY, default = DEFAULT_ICON,
values = iconTypes, values = mapOf(
"Bold" to DEFAULT_ICON,
"Rounded" to "rounded",
"Thin" to "thin"
),
title = "Icon type", title = "Icon type",
description = "The icon type.", description = "The icon type.",
required = true required = true
) )
// Option to set bottom margin // Option to set bottom margin
private val BottomMargin by stringPatchOption( private val BottomMargin = stringPatchOption(
key = "BottomMargin", key = "BottomMargin",
default = DEFAULT_MARGIN, default = DEFAULT_MARGIN,
values = mapOf( values = mapOf(
@ -76,6 +74,13 @@ object OverlayButtonsPatch : BaseResourcePatch(
*/ */
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// Check patch options first.
val iconType = IconType
.lowerCaseOrThrow()
val marginBottom = BottomMargin
.lowerCaseOrThrow()
// Inject hooks for overlay buttons. // Inject hooks for overlay buttons.
arrayOf( arrayOf(
"AlwaysRepeat;", "AlwaysRepeat;",
@ -101,9 +106,7 @@ object OverlayButtonsPatch : BaseResourcePatch(
context.copyResources("youtube/overlaybuttons/shared", resourceGroup) context.copyResources("youtube/overlaybuttons/shared", resourceGroup)
} }
// Apply the selected icon type to the overlay buttons // Apply the selected icon type to the overlay buttons.
IconType?.let { iconType ->
val iconValue = iconType.lowercase()
val commonResources = arrayOf( val commonResources = arrayOf(
"ic_fullscreen_vertical_button.png", "ic_fullscreen_vertical_button.png",
"ic_vr.png", "ic_vr.png",
@ -123,7 +126,7 @@ object OverlayButtonsPatch : BaseResourcePatch(
"yt_outline_screen_full_exit_white_24.png", "yt_outline_screen_full_exit_white_24.png",
"yt_outline_screen_full_white_24.png" "yt_outline_screen_full_white_24.png"
) )
val specificResources = if (iconValue == "thin") { val specificResources = if (iconType == "thin") {
arrayOf("yt_outline_screen_vertical_vd_theme_24.xml") arrayOf("yt_outline_screen_vertical_vd_theme_24.xml")
} else { } else {
arrayOf("yt_outline_screen_vertical_vd_theme_24.png") arrayOf("yt_outline_screen_vertical_vd_theme_24.png")
@ -132,11 +135,10 @@ object OverlayButtonsPatch : BaseResourcePatch(
resources.forEach { resource -> resources.forEach { resource ->
val folderName = if (resource.endsWith(".xml")) "drawable" else "drawable-xxhdpi" val folderName = if (resource.endsWith(".xml")) "drawable" else "drawable-xxhdpi"
context.copyResources( context.copyResources(
"youtube/overlaybuttons/$iconValue", "youtube/overlaybuttons/$iconType",
ResourceGroup(folderName, resource) ResourceGroup(folderName, resource)
) )
} }
}
// Merge XML nodes from the host to their respective XML files. // Merge XML nodes from the host to their respective XML files.
context.copyXmlNode( context.copyXmlNode(
@ -145,9 +147,6 @@ object OverlayButtonsPatch : BaseResourcePatch(
"android.support.constraint.ConstraintLayout" "android.support.constraint.ConstraintLayout"
) )
val marginBottom = BottomMargin
?: DEFAULT_MARGIN
// Modify the layout of fullscreen button for newer YouTube versions (19.09.xx+) // Modify the layout of fullscreen button for newer YouTube versions (19.09.xx+)
arrayOf( arrayOf(
"youtube_controls_cf_fullscreen_button.xml", "youtube_controls_cf_fullscreen_button.xml",

View File

@ -18,6 +18,7 @@ import app.revanced.util.copyResources
import app.revanced.util.copyXmlNode import app.revanced.util.copyXmlNode
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.patch.BaseResourcePatch import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.valueOrThrow
import org.w3c.dom.Element import org.w3c.dom.Element
import java.io.Closeable import java.io.Closeable
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -38,7 +39,7 @@ object SettingsPatch : BaseResourcePatch(
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
requiresIntegrations = true requiresIntegrations = true
), Closeable { ), Closeable {
private const val DEFAULT_ELEMENT = "About" private const val DEFAULT_ELEMENT = "@string/about_key"
private const val DEFAULT_NAME = "ReVanced Extended" private const val DEFAULT_NAME = "ReVanced Extended"
private val SETTINGS_ELEMENTS_MAP = mapOf( private val SETTINGS_ELEMENTS_MAP = mapOf(
@ -63,10 +64,10 @@ object SettingsPatch : BaseResourcePatch(
"Live chat" to "@string/live_chat_key", "Live chat" to "@string/live_chat_key",
"Captions" to "@string/captions_key", "Captions" to "@string/captions_key",
"Accessibility" to "@string/accessibility_settings_key", "Accessibility" to "@string/accessibility_settings_key",
DEFAULT_ELEMENT to "@string/about_key" "About" to DEFAULT_ELEMENT
) )
private val InsertPosition by stringPatchOption( private val InsertPosition = stringPatchOption(
key = "InsertPosition", key = "InsertPosition",
default = DEFAULT_ELEMENT, default = DEFAULT_ELEMENT,
values = SETTINGS_ELEMENTS_MAP, values = SETTINGS_ELEMENTS_MAP,
@ -75,7 +76,7 @@ object SettingsPatch : BaseResourcePatch(
required = true required = true
) )
private val RVXSettingsMenuName by stringPatchOption( private val RVXSettingsMenuName = stringPatchOption(
key = "RVXSettingsMenuName", key = "RVXSettingsMenuName",
default = DEFAULT_NAME, default = DEFAULT_NAME,
title = "RVX settings menu name", title = "RVX settings menu name",
@ -83,6 +84,8 @@ object SettingsPatch : BaseResourcePatch(
required = true required = true
) )
private lateinit var customName: String
internal lateinit var contexts: ResourceContext internal lateinit var contexts: ResourceContext
internal var upward1831 = false internal var upward1831 = false
internal var upward1834 = false internal var upward1834 = false
@ -94,6 +97,15 @@ object SettingsPatch : BaseResourcePatch(
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
/**
* check patch options
*/
customName = RVXSettingsMenuName
.valueOrThrow()
val insertKey = InsertPosition
.valueOrThrow()
/** /**
* set resource context * set resource context
*/ */
@ -148,16 +160,10 @@ object SettingsPatch : BaseResourcePatch(
/** /**
* initialize ReVanced Extended Settings * initialize ReVanced Extended Settings
*/ */
val elementKey = SETTINGS_ELEMENTS_MAP[InsertPosition]
?: InsertPosition
?: SETTINGS_ELEMENTS_MAP[DEFAULT_ELEMENT]
elementKey?.let { insertKey ->
context.addPreferenceFragment( context.addPreferenceFragment(
"revanced_extended_settings", "revanced_extended_settings",
insertKey insertKey
) )
}
/** /**
* remove ReVanced Extended Settings divider * remove ReVanced Extended Settings divider
@ -220,7 +226,6 @@ object SettingsPatch : BaseResourcePatch(
* change RVX settings menu name * change RVX settings menu name
* since it must be invoked after the Translations patch, it must be the last in the order. * since it must be invoked after the Translations patch, it must be the last in the order.
*/ */
RVXSettingsMenuName?.let { customName ->
if (customName != DEFAULT_NAME) { if (customName != DEFAULT_NAME) {
contexts.removeStringsElements( contexts.removeStringsElements(
arrayOf("revanced_extended_settings_title") arrayOf("revanced_extended_settings_title")
@ -241,8 +246,6 @@ object SettingsPatch : BaseResourcePatch(
} }
} }
} }
} ?: println("WARNING: Invalid RVX settings menu name. RVX settings menu name does not change.")
} }
private fun setVersionInfo() { private fun setVersionInfo() {

View File

@ -3,15 +3,27 @@
package app.revanced.util package app.revanced.util
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.options.PatchOption
import app.revanced.patcher.util.DomFileEditor import app.revanced.patcher.util.DomFileEditor
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.Node import org.w3c.dom.Node
import java.io.File
import java.io.InputStream import java.io.InputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
val classLoader: ClassLoader = object {}.javaClass.classLoader val classLoader: ClassLoader = object {}.javaClass.classLoader
fun PatchOption<String>.valueOrThrow() = value
?: throw PatchException("Invalid patch option: $title.")
fun PatchOption<String>.lowerCaseOrThrow() = valueOrThrow()
.lowercase()
fun PatchOption<String>.underBarOrThrow() = lowerCaseOrThrow()
.replace(" ", "_")
fun Node.adoptChild(tagName: String, block: Element.() -> Unit) { fun Node.adoptChild(tagName: String, block: Element.() -> Unit) {
val child = ownerDocument.createElement(tagName) val child = ownerDocument.createElement(tagName)
child.block() child.block()
@ -48,6 +60,36 @@ fun String.startsWithAny(vararg prefixes: String): Boolean {
return false return false
} }
fun ResourceContext.copyFile(
resourceGroup: List<ResourceGroup>,
path: String,
warning: String
): Boolean {
resourceGroup.let { resourceGroups ->
try {
val filePath = File(path)
val resourceDirectory = this["res"]
resourceGroups.forEach { group ->
val fromDirectory = filePath.resolve(group.resourceDirectoryName)
val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName)
group.resources.forEach { iconFileName ->
Files.write(
toDirectory.resolve(iconFileName).toPath(),
fromDirectory.resolve(iconFileName).readBytes()
)
}
}
return true
} catch (_: Exception) {
println(warning)
}
}
return false
}
/** /**
* Copy resources from the current class loader to the resource directory. * Copy resources from the current class loader to the resource directory.
* *