diff --git a/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/CustomBrandingIconPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/CustomBrandingIconPatch.kt index 71c8a8458..e7c39f05c 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/CustomBrandingIconPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/CustomBrandingIconPatch.kt @@ -9,6 +9,7 @@ import app.revanced.util.ResourceGroup import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.copyResources import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.underBarOrThrow import java.io.File 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.", compatiblePackages = COMPATIBLE_PACKAGE ) { - private const val DEFAULT_ICON_KEY = "Revancify Blue" + private const val DEFAULT_ICON = "revancify_blue" private val availableIcon = mapOf( "AFN Blue" to "afn_blue", "AFN Red" to "afn_red", "MMT" to "mmt", - DEFAULT_ICON_KEY to "revancify_blue", + "Revancify Blue" to DEFAULT_ICON, "Revancify Red" to "revancify_red", "YouTube Music" to "youtube_music" ) @@ -93,9 +94,9 @@ object CustomBrandingIconPatch : BaseResourcePatch( ) } - private val AppIcon by stringPatchOption( + private val AppIcon = stringPatchOption( key = "AppIcon", - default = DEFAULT_ICON_KEY, + default = DEFAULT_ICON, values = availableIcon, title = "App icon", description = """ @@ -129,70 +130,72 @@ object CustomBrandingIconPatch : BaseResourcePatch( ) override fun execute(context: ResourceContext) { - AppIcon?.let { appIcon -> - val appIconValue = appIcon.lowercase().replace(" ", "_") - val appIconResourcePath = "music/branding/$appIconValue" - // Check if a custom path is used in the patch options. - if (!availableIcon.containsValue(appIconValue)) { - launcherIconResourceGroups.let { resourceGroups -> - try { - val path = File(appIcon) - val resourceDirectory = context["res"] + // Check patch options first. + val appIcon = AppIcon + .underBarOrThrow() - resourceGroups.forEach { group -> - val fromDirectory = path.resolve(group.resourceDirectoryName) - val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName) + val appIconResourcePath = "music/branding/$appIcon" - group.resources.forEach { iconFileName -> - Files.write( - toDirectory.resolve(iconFileName).toPath(), - fromDirectory.resolve(iconFileName).readBytes() - ) - } + // Check if a custom path is used in the patch options. + if (!availableIcon.containsValue(appIcon)) { + launcherIconResourceGroups.let { resourceGroups -> + try { + val path = File(appIcon) + val resourceDirectory = context["res"] + + resourceGroups.forEach { group -> + val fromDirectory = path.resolve(group.resourceDirectoryName) + val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName) + + group.resources.forEach { iconFileName -> + Files.write( + toDirectory.resolve(iconFileName).toPath(), + fromDirectory.resolve(iconFileName).readBytes() + ) } - } catch (_: Exception) { - // Exception is thrown if an invalid path is used in the patch option. - throw PatchException("Invalid app icon path: $appIcon") } + } catch (_: Exception) { + // Exception is thrown if an invalid path is used in the patch option. + throw PatchException("Invalid app icon path: $appIcon") } - } else { + } + } else { - // Change launcher icon. - launcherIconResourceGroups.let { resourceGroups -> + // Change launcher icon. + launcherIconResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + context.copyResources("$appIconResourcePath/launcher", it) + } + } + + // Change monochrome icon. + arrayOf( + ResourceGroup( + "drawable", + "ic_app_icons_themed_youtube_music.xml" + ) + ).forEach { resourceGroup -> + context.copyResources("$appIconResourcePath/monochrome", resourceGroup) + } + + // Change header. + if (ChangeHeader == true) { + headerIconResourceGroups.let { resourceGroups -> resourceGroups.forEach { - context.copyResources("$appIconResourcePath/launcher", it) - } - } - - // Change monochrome icon. - arrayOf( - ResourceGroup( - "drawable", - "ic_app_icons_themed_youtube_music.xml" - ) - ).forEach { resourceGroup -> - context.copyResources("$appIconResourcePath/monochrome", resourceGroup) - } - - // Change header. - if (ChangeHeader == true) { - headerIconResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - context.copyResources("$appIconResourcePath/header", it) - } - } - } - - // Change splash icon. - if (ChangeSplashIcon == true) { - splashIconResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - context.copyResources("$appIconResourcePath/splash", it) - } + context.copyResources("$appIconResourcePath/header", it) } } } - } ?: throw PatchException("Invalid app icon path.") + + // Change splash icon. + if (ChangeSplashIcon == true) { + splashIconResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + context.copyResources("$appIconResourcePath/splash", it) + } + } + } + } } } diff --git a/src/main/kotlin/app/revanced/patches/music/layout/branding/name/CustomBrandingNamePatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/branding/name/CustomBrandingNamePatch.kt index 021f8c65e..9d161a74d 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/branding/name/CustomBrandingNamePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/branding/name/CustomBrandingNamePatch.kt @@ -1,11 +1,11 @@ package app.revanced.patches.music.layout.branding.name import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow @Suppress("DEPRECATION", "unused") object CustomBrandingNamePatch : BaseResourcePatch( @@ -16,7 +16,7 @@ object CustomBrandingNamePatch : BaseResourcePatch( private const val APP_NAME_NOTIFICATION = "ReVanced Extended Music" private const val APP_NAME_LAUNCHER = "RVX Music" - private val AppNameNotification by stringPatchOption( + private val AppNameNotification = stringPatchOption( key = "AppNameNotification", default = APP_NAME_LAUNCHER, values = mapOf( @@ -30,7 +30,7 @@ object CustomBrandingNamePatch : BaseResourcePatch( required = true ) - private val AppNameLauncher by stringPatchOption( + private val AppNameLauncher = stringPatchOption( key = "AppNameLauncher", default = APP_NAME_LAUNCHER, values = mapOf( @@ -46,29 +46,31 @@ object CustomBrandingNamePatch : BaseResourcePatch( override fun execute(context: ResourceContext) { + // Check patch options first. + val notificationName = AppNameNotification + .valueOrThrow() + val launcherName = AppNameLauncher + .valueOrThrow() + context.removeStringsElements( arrayOf("app_launcher_name", "app_name") ) - AppNameNotification?.let { notificationName -> - AppNameLauncher?.let { launcherName -> - context.xmlEditor["res/values/strings.xml"].use { editor -> - val document = editor.file + context.xmlEditor["res/values/strings.xml"].use { editor -> + val document = editor.file - mapOf( - "app_name" to notificationName, - "app_launcher_name" to launcherName - ).forEach { (k, v) -> - val stringElement = document.createElement("string") + mapOf( + "app_name" to notificationName, + "app_launcher_name" to launcherName + ).forEach { (k, v) -> + val stringElement = document.createElement("string") - stringElement.setAttribute("name", k) - stringElement.textContent = v + stringElement.setAttribute("name", k) + stringElement.textContent = v - document.getElementsByTagName("resources").item(0) - .appendChild(stringElement) - } - } - } ?: throw PatchException("Invalid launcher name.") - } ?: throw PatchException("Invalid notification name.") + document.getElementsByTagName("resources").item(0) + .appendChild(stringElement) + } + } } } diff --git a/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt index 558547e6c..f00dc88f6 100644 --- a/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/settings/SettingsPatch.kt @@ -12,6 +12,7 @@ import app.revanced.patches.music.utils.settings.ResourceUtils.sortPreferenceCat import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements import app.revanced.util.copyXmlNode import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow import org.w3c.dom.Element import java.io.Closeable import java.util.concurrent.Executors @@ -30,7 +31,7 @@ object SettingsPatch : BaseResourcePatch( ), Closeable { private const val DEFAULT_NAME = "ReVanced Extended" - private val RVXSettingsMenuName by stringPatchOption( + private val RVXSettingsMenuName = stringPatchOption( key = "RVXSettingsMenuName", default = DEFAULT_NAME, title = "RVX settings menu name", @@ -38,12 +39,20 @@ object SettingsPatch : BaseResourcePatch( required = true ) + private lateinit var customName: String + lateinit var contexts: ResourceContext internal var upward0636 = false internal var upward0642 = false override fun execute(context: ResourceContext) { + /** + * check patch options + */ + customName = RVXSettingsMenuName + .valueOrThrow() + /** * set resource context */ @@ -193,35 +202,38 @@ object SettingsPatch : BaseResourcePatch( * change RVX settings menu name * since it must be invoked after the Translations patch, it must be the last in the order. */ - RVXSettingsMenuName?.let { customName -> - if (customName != DEFAULT_NAME) { - contexts.removeStringsElements( - arrayOf("revanced_extended_settings_title") - ) - contexts.xmlEditor["res/values/strings.xml"].use { editor -> - val document = editor.file + if (customName != DEFAULT_NAME) { + contexts.removeStringsElements( + arrayOf("revanced_extended_settings_title") + ) + contexts.xmlEditor["res/values/strings.xml"].use { editor -> + val document = editor.file - mapOf( - "revanced_extended_settings_title" to customName - ).forEach { (k, v) -> - val stringElement = document.createElement("string") + mapOf( + "revanced_extended_settings_title" to customName + ).forEach { (k, v) -> + val stringElement = document.createElement("string") - stringElement.setAttribute("name", k) - stringElement.textContent = v + stringElement.setAttribute("name", k) + stringElement.textContent = v - document.getElementsByTagName("resources").item(0) - .appendChild(stringElement) - } + document.getElementsByTagName("resources").item(0) + .appendChild(stringElement) } } - } ?: println("WARNING: Invalid RVX settings menu name. RVX settings menu name does not change.") - + } + /** + * add import export settings + */ addPreferenceWithIntent( CategoryType.MISC, "revanced_extended_settings_import_export" ) + /** + * sort preference + */ CategoryType.entries.sorted().forEach { contexts.sortPreferenceCategory(it.value) } diff --git a/src/main/kotlin/app/revanced/patches/reddit/layout/branding/name/CustomBrandingNamePatch.kt b/src/main/kotlin/app/revanced/patches/reddit/layout/branding/name/CustomBrandingNamePatch.kt index 95c609ca5..29968ff2c 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/layout/branding/name/CustomBrandingNamePatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/layout/branding/name/CustomBrandingNamePatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow import java.io.FileWriter import java.nio.file.Files @@ -17,7 +18,7 @@ object CustomBrandingNamePatch : BaseResourcePatch( private const val ORIGINAL_APP_NAME = "Reddit" private const val APP_NAME = "RVX Reddit" - private val AppName by stringPatchOption( + private val AppName = stringPatchOption( key = "AppName", default = ORIGINAL_APP_NAME, values = mapOf( @@ -30,44 +31,41 @@ object CustomBrandingNamePatch : BaseResourcePatch( ) override fun execute(context: ResourceContext) { - val appName = if (AppName != null) { - AppName!! - } else { - println("WARNING: Invalid app name. Does not apply patches.") - ORIGINAL_APP_NAME + val appName = AppName + .valueOrThrow() + + if (appName == 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") - if (!valuesV24Directory.isDirectory) - Files.createDirectories(valuesV24Directory.toPath()) + val valuesV24Directory = resDirectory.resolve("values-v24") + if (!valuesV24Directory.isDirectory) + Files.createDirectories(valuesV24Directory.toPath()) - val stringsXml = valuesV24Directory.resolve("strings.xml") + val stringsXml = valuesV24Directory.resolve("strings.xml") - if (!stringsXml.exists()) { - FileWriter(stringsXml).use { - it.write("") - } + if (!stringsXml.exists()) { + FileWriter(stringsXml).use { + it.write("") } + } - context.xmlEditor["res/values-v24/strings.xml"].use { editor -> - val document = editor.file + context.xmlEditor["res/values-v24/strings.xml"].use { editor -> + val document = editor.file - mapOf( - "app_name" to appName - ).forEach { (k, v) -> - val stringElement = document.createElement("string") + mapOf( + "app_name" to appName + ).forEach { (k, v) -> + val stringElement = document.createElement("string") - stringElement.setAttribute("name", k) - stringElement.textContent = v + stringElement.setAttribute("name", k) + stringElement.textContent = v - 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.") } } } diff --git a/src/main/kotlin/app/revanced/patches/reddit/layout/branding/packagename/ChangePackageNamePatch.kt b/src/main/kotlin/app/revanced/patches/reddit/layout/branding/packagename/ChangePackageNamePatch.kt index f33af78a1..5bfd6d575 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/layout/branding/packagename/ChangePackageNamePatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/layout/branding/packagename/ChangePackageNamePatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow import org.w3c.dom.Element import java.io.Closeable @@ -21,7 +22,7 @@ object ChangePackageNamePatch : BaseResourcePatch( private lateinit var context: ResourceContext private var redditPackageName = PACKAGE_NAME_REDDIT - private val PackageNameReddit by stringPatchOption( + private val PackageNameReddit = stringPatchOption( key = "PackageNameReddit", default = PACKAGE_NAME_REDDIT, values = mapOf( @@ -37,26 +38,25 @@ object ChangePackageNamePatch : BaseResourcePatch( override fun execute(context: ResourceContext) { this.context = context - if (PackageNameReddit != null) { - redditPackageName = PackageNameReddit!! - } else { - println("WARNING: Invalid package name. Does not apply patches.") + redditPackageName = PackageNameReddit + .valueOrThrow() + + 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. - try { - // RVX Manager - // ==== - // 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 - Class.forName("android.os.Environment") - } catch (_: ClassNotFoundException) { - // CLI - context.replacePackageName(redditPackageName) - } - } else { - println("INFO: Package name will remain unchanged as it matches the original.") + // Ensure device runs Android. + try { + // RVX Manager + // ==== + // 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 + Class.forName("android.os.Environment") + return + } catch (_: ClassNotFoundException) { + // CLI + context.replacePackageName(redditPackageName) } } diff --git a/src/main/kotlin/app/revanced/patches/reddit/utils/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/utils/settings/SettingsPatch.kt index f4f202c73..4edff9682 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/utils/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/utils/settings/SettingsPatch.kt @@ -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.integrations.IntegrationsPatch import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow import kotlin.io.path.exists @Suppress("DEPRECATION") @@ -21,7 +22,7 @@ object SettingsPatch : BaseResourcePatch( ) { private const val DEFAULT_NAME = "ReVanced Extended" - private val RVXSettingsMenuName by stringPatchOption( + private val RVXSettingsMenuName = stringPatchOption( key = "RVXSettingsMenuName", default = DEFAULT_NAME, title = "RVX settings menu name", @@ -32,11 +33,8 @@ object SettingsPatch : BaseResourcePatch( /** * Replace settings icon and label */ - - var settingsLabel = DEFAULT_NAME - - if (!RVXSettingsMenuName.isNullOrEmpty()) - settingsLabel = RVXSettingsMenuName!! + val settingsLabel = RVXSettingsMenuName + .valueOrThrow() arrayOf("preferences", "preferences_logged_in").forEach { targetXML -> val resDirectory = context["res"] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt index 9f3272f70..dad721bda 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt @@ -1,12 +1,12 @@ package app.revanced.patches.youtube.layout.actionbuttons import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchException 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.settings.SettingsPatch import app.revanced.util.ResourceGroup import app.revanced.util.copyResources +import app.revanced.util.lowerCaseOrThrow import app.revanced.util.patch.BaseResourcePatch @Suppress("unused") @@ -16,15 +16,15 @@ object ShortsActionButtonsPatch : BaseResourcePatch( dependencies = setOf(SettingsPatch::class), 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", - default = DEFAULT_ICON_KEY, + default = DEFAULT_ICON, values = mapOf( "Outline" to "outline", "OutlineCircle" to "outlinecircle", - DEFAULT_ICON_KEY to "round" + "Round" to DEFAULT_ICON ), title = "Shorts icon style ", description = "The style of the icons for the action buttons in the Shorts player.", @@ -32,53 +32,54 @@ object ShortsActionButtonsPatch : BaseResourcePatch( ) override fun execute(context: ResourceContext) { - IconType?.let { iconType -> - val selectedIconType = iconType.lowercase() - arrayOf( - "xxxhdpi", - "xxhdpi", - "xhdpi", - "hdpi", - "mdpi" - ).forEach { dpi -> - context.copyResources( - "youtube/shorts/actionbuttons/$selectedIconType", - ResourceGroup( - "drawable-$dpi", - "ic_remix_filled_white_shadowed.webp", - "ic_right_comment_shadowed.webp", - "ic_right_dislike_off_shadowed.webp", - "ic_right_dislike_on_shadowed.webp", - "ic_right_like_off_shadowed.webp", - "ic_right_like_on_shadowed.webp", - "ic_right_share_shadowed.webp", + // Check patch options first. + val iconType = IconType + .lowerCaseOrThrow() - // for older versions only - "ic_remix_filled_white_24.webp", - "ic_right_dislike_on_32c.webp", - "ic_right_like_on_32c.webp" - ), - ResourceGroup( - "drawable", - "ic_right_comment_32c.xml", - "ic_right_dislike_off_32c.xml", - "ic_right_like_off_32c.xml", - "ic_right_share_32c.xml" - ) + arrayOf( + "xxxhdpi", + "xxhdpi", + "xhdpi", + "hdpi", + "mdpi" + ).forEach { dpi -> + context.copyResources( + "youtube/shorts/actionbuttons/$iconType", + ResourceGroup( + "drawable-$dpi", + "ic_remix_filled_white_shadowed.webp", + "ic_right_comment_shadowed.webp", + "ic_right_dislike_off_shadowed.webp", + "ic_right_dislike_on_shadowed.webp", + "ic_right_like_off_shadowed.webp", + "ic_right_like_on_shadowed.webp", + "ic_right_share_shadowed.webp", + + // for older versions only + "ic_remix_filled_white_24.webp", + "ic_right_dislike_on_32c.webp", + "ic_right_like_on_32c.webp" + ), + ResourceGroup( + "drawable", + "ic_right_comment_32c.xml", + "ic_right_dislike_off_32c.xml", + "ic_right_like_off_32c.xml", + "ic_right_share_32c.xml" ) + ) + } - context.copyResources( - "youtube/shorts/actionbuttons/shared", - ResourceGroup( - "drawable", - "reel_camera_bold_24dp.xml", - "reel_more_vertical_bold_24dp.xml", - "reel_search_bold_24dp.xml" - ) - ) - } - } ?: throw PatchException("Invalid icon type.") + context.copyResources( + "youtube/shorts/actionbuttons/shared", + ResourceGroup( + "drawable", + "reel_camera_bold_24dp.xml", + "reel_more_vertical_bold_24dp.xml", + "reel_search_bold_24dp.xml" + ) + ) SettingsPatch.updatePatchStatus(this) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt index ab6c75943..73fababf4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt @@ -1,7 +1,6 @@ package app.revanced.patches.youtube.layout.branding.icon 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.stringPatchOption 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.util.ResourceGroup import app.revanced.util.Utils.trimIndentMultiline +import app.revanced.util.copyFile import app.revanced.util.copyResources import app.revanced.util.copyXmlNode import app.revanced.util.patch.BaseResourcePatch -import java.io.File -import java.nio.file.Files +import app.revanced.util.underBarOrThrow -@Suppress("DEPRECATION", "unused") +@Suppress("unused") object CustomBrandingIconPatch : BaseResourcePatch( name = "Custom branding icon YouTube", description = "Changes the YouTube app icon to the icon specified in options.json.", dependencies = setOf(SettingsPatch::class), compatiblePackages = COMPATIBLE_PACKAGE, ) { - private const val DEFAULT_ICON_KEY = "Revancify Blue" + private const val DEFAULT_ICON = "revancify_blue" private val availableIcon = mapOf( "AFN Blue" to "afn_blue", "AFN Red" to "afn_red", "MMT" to "mmt", - DEFAULT_ICON_KEY to "revancify_blue", + "Revancify Blue" to DEFAULT_ICON, "Revancify Red" to "revancify_red", "YouTube" to "youtube" ) @@ -109,9 +108,9 @@ object CustomBrandingIconPatch : BaseResourcePatch( // region patch option - val AppIcon by stringPatchOption( + val AppIcon = stringPatchOption( key = "AppIcon", - default = DEFAULT_ICON_KEY, + default = DEFAULT_ICON, values = availableIcon, title = "App icon", description = """ @@ -176,112 +175,84 @@ object CustomBrandingIconPatch : BaseResourcePatch( // endregion override fun execute(context: ResourceContext) { - AppIcon?.let { appIcon -> - val appIconValue = appIcon.lowercase().replace(" ", "_") - val appIconResourcePath = "youtube/branding/$appIconValue" - val stockResourcePath = "youtube/branding/stock" - // Check if a custom path is used in the patch options. - if (!availableIcon.containsValue(appIconValue)) { - val copiedFiles = context.copyFile( - launcherIconResourceGroups, - appIcon, - "WARNING: Invalid app icon path: $appIcon. Does not apply patches." + // Check patch options first. + val appIcon = AppIcon + .underBarOrThrow() + + val appIconResourcePath = "youtube/branding/$appIcon" + val stockResourcePath = "youtube/branding/stock" + + // Check if a custom path is used in the patch options. + if (!availableIcon.containsValue(appIcon)) { + val copiedFiles = context.copyFile( + launcherIconResourceGroups, + appIcon, + "WARNING: Invalid app icon path: $appIcon. Does not apply patches." + ) + if (copiedFiles) + context.updatePatchStatusIcon("custom") + } else { + // Change launcher icon. + launcherIconResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + context.copyResources("$appIconResourcePath/launcher", it) + } + } + + // Change monochrome icon. + arrayOf( + ResourceGroup( + "drawable", + "adaptive_monochrome_ic_youtube_launcher.xml" ) - if (copiedFiles) - context.updatePatchStatusIcon("custom") - } else { - // Change launcher icon. - launcherIconResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - context.copyResources("$appIconResourcePath/launcher", it) + ).forEach { resourceGroup -> + context.copyResources("$appIconResourcePath/monochrome", resourceGroup) + } + + // Change header. + if (ChangeHeader == true) { + CustomHeader?.let { customHeader -> + var copiedFiles = false + if (customHeader.isNotEmpty()) { + copiedFiles = context.copyFile( + headerIconResourceGroups, + customHeader, + "WARNING: Invalid header path: $customHeader. Does not apply patches." + ) } - } - - // Change monochrome icon. - arrayOf( - ResourceGroup( - "drawable", - "adaptive_monochrome_ic_youtube_launcher.xml" - ) - ).forEach { resourceGroup -> - context.copyResources("$appIconResourcePath/monochrome", resourceGroup) - } - - // Change header. - if (ChangeHeader == true) { - CustomHeader?.let { customHeader -> - var copiedFiles = false - if (customHeader.isNotEmpty()) { - copiedFiles = context.copyFile( - headerIconResourceGroups, - customHeader, - "WARNING: Invalid header path: $customHeader. Does not apply patches." - ) - } - if (!copiedFiles) { - headerIconResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - context.copyResources("$appIconResourcePath/header", it) - } + if (!copiedFiles) { + headerIconResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + context.copyResources("$appIconResourcePath/header", it) } } } } - - // Change splash icon. - if (ChangeSplashIcon == true) { - splashIconResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - context.copyResources("$appIconResourcePath/splash", it) - } - } - } - - // Change splash screen. - if (RestoreOldSplashAnimation == true) { - oldSplashAnimationResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - context.copyResources("$stockResourcePath/splash", it) - context.copyResources("$appIconResourcePath/splash", it) - } - } - - context.copyXmlNode("$stockResourcePath/splash", "values-v31/styles.xml", "resources") - } - - context.updatePatchStatusIcon(appIconValue) } - } ?: throw PatchException("Invalid app icon path.") - } - private fun ResourceContext.copyFile( - iconResourceGroup: List, - path: String, - message: String - ): Boolean { - iconResourceGroup.let { resourceGroups -> - try { - val filePath = File(path) - val resourceDirectory = this["res"] + // Change splash icon. + if (ChangeSplashIcon == true) { + splashIconResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + context.copyResources("$appIconResourcePath/splash", it) + } + } + } - 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() - ) + // Change splash screen. + if (RestoreOldSplashAnimation == true) { + oldSplashAnimationResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + context.copyResources("$stockResourcePath/splash", it) + context.copyResources("$appIconResourcePath/splash", it) } } - return true - } catch (_: Exception) { - println(message) + context.copyXmlNode("$stockResourcePath/splash", "values-v31/styles.xml", "resources") } + + context.updatePatchStatusIcon(appIcon) } - return false } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/name/CustomBrandingNamePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/name/CustomBrandingNamePatch.kt index 01e0e79c2..c351e9160 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/name/CustomBrandingNamePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/name/CustomBrandingNamePatch.kt @@ -1,13 +1,13 @@ package app.revanced.patches.youtube.layout.branding.name import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements 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.SettingsPatch import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow @Suppress("DEPRECATION", "unused") object CustomBrandingNamePatch : BaseResourcePatch( @@ -18,7 +18,7 @@ object CustomBrandingNamePatch : BaseResourcePatch( ) { private const val APP_NAME = "RVX" - private val AppName by stringPatchOption( + private val AppName = stringPatchOption( key = "AppName", default = APP_NAME, values = mapOf( @@ -33,26 +33,29 @@ object CustomBrandingNamePatch : BaseResourcePatch( ) override fun execute(context: ResourceContext) { + + // Check patch options first. + val appName = AppName + .valueOrThrow() + context.removeStringsElements( arrayOf("application_name") ) - AppName?.let { - context.xmlEditor["res/values/strings.xml"].use { editor -> - val document = editor.file + context.xmlEditor["res/values/strings.xml"].use { editor -> + val document = editor.file - mapOf( - "application_name" to it - ).forEach { (k, v) -> - val stringElement = document.createElement("string") + mapOf( + "application_name" to appName + ).forEach { (k, v) -> + val stringElement = document.createElement("string") - stringElement.setAttribute("name", k) - stringElement.textContent = v + stringElement.setAttribute("name", k) + stringElement.textContent = v - document.getElementsByTagName("resources").item(0).appendChild(stringElement) - } + document.getElementsByTagName("resources").item(0).appendChild(stringElement) } - context.updatePatchStatusLabel(it) - } ?: throw PatchException("Invalid app name.") + } + context.updatePatchStatusLabel(appName) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/doubletaplength/DoubleTapLengthPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/doubletaplength/DoubleTapLengthPatch.kt index e3e2ced6a..170a03a33 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/doubletaplength/DoubleTapLengthPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/doubletaplength/DoubleTapLengthPatch.kt @@ -27,6 +27,15 @@ object DoubleTapLengthPatch : BaseResourcePatch( ) 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 entriesName = "double_tap_length_entries" 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()) { context.addEntryValues(arrayPath, lengthElements[index], entryValueName) context.addEntryValues(arrayPath, lengthElements[index], entriesName) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt index 32f74d47e..f6c0d58a4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt @@ -1,13 +1,13 @@ package app.revanced.patches.youtube.layout.theme import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption 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.settings.ResourceUtils.updatePatchStatusTheme import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow import org.w3c.dom.Element @Suppress("DEPRECATION", "unused") @@ -38,7 +38,7 @@ object ThemePatch : BaseResourcePatch( private const val LIGHT_ORANGE_COLOR = "#FFFFE6CC" private const val LIGHT_RED_COLOR = "#FFFFD6D6" - private val DarkThemeBackgroundColor by stringPatchOption( + private val DarkThemeBackgroundColor = stringPatchOption( key = "DarkThemeBackgroundColor", default = AMOLED_BLACK_COLOR, values = mapOf( @@ -56,7 +56,7 @@ object ThemePatch : BaseResourcePatch( required = true ) - private val LightThemeBackgroundColor by stringPatchOption( + private val LightThemeBackgroundColor = stringPatchOption( key = "LightThemeBackgroundColor", default = WHITE_COLOR, values = mapOf( @@ -111,11 +111,12 @@ object ThemePatch : BaseResourcePatch( override fun execute(context: ResourceContext) { + // Check patch options first. val darkThemeColor = DarkThemeBackgroundColor - ?: throw PatchException("Invalid dark color.") + .valueOrThrow() val lightThemeColor = LightThemeBackgroundColor - ?: throw PatchException("Invalid light color.") + .valueOrThrow() arrayOf("values", "values-v31").forEach { path -> context.xmlEditor["res/$path/colors.xml"].use { editor -> diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt index 44783280d..40fb7477f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/visual/VisualPreferencesIconsPatch.kt @@ -1,6 +1,7 @@ package app.revanced.patches.youtube.layout.visual import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patches.youtube.layout.branding.icon.CustomBrandingIconPatch 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.doRecursively import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.underBarOrThrow import org.w3c.dom.Element @Suppress("DEPRECATION", "unused") @@ -19,14 +21,14 @@ object VisualPreferencesIconsPatch : BaseResourcePatch( compatiblePackages = COMPATIBLE_PACKAGE, 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", - default = DEFAULT_ICON_KEY, + default = DEFAULT_ICON, values = mapOf( "Custom branding icon" to "custom_branding_icon", - DEFAULT_ICON_KEY to "extension", + "Extension" to DEFAULT_ICON, "Gear" to "gear", "ReVanced" to "revanced", "ReVanced Colored" to "revanced_colored", @@ -38,6 +40,13 @@ object VisualPreferencesIconsPatch : BaseResourcePatch( override fun execute(context: ResourceContext) { + // Check patch options first. + val selectedIconType = RVXSettingsMenuIcon + .underBarOrThrow() + + val customBrandingIconType = CustomBrandingIconPatch.AppIcon + .underBarOrThrow() + // region copy shared resources. arrayOf( @@ -57,31 +66,27 @@ object VisualPreferencesIconsPatch : BaseResourcePatch( // region copy RVX settings menu icon. - RVXSettingsMenuIcon?.lowercase()?.replace(" ", "_")?.let { selectedIconType -> - CustomBrandingIconPatch.AppIcon?.lowercase()?.replace(" ", "_")?.let { appIconValue -> - val fallbackIconPath = "youtube/visual/icons/extension" - val iconPath = when (selectedIconType) { - "custom_branding_icon" -> "youtube/branding/$appIconValue/settings" - else -> "youtube/visual/icons/$selectedIconType" - } - val resourceGroup = ResourceGroup( - "drawable", - "revanced_extended_settings_key_icon.xml" - ) + val fallbackIconPath = "youtube/visual/icons/extension" + val iconPath = when (selectedIconType) { + "custom_branding_icon" -> "youtube/branding/$customBrandingIconType/settings" + else -> "youtube/visual/icons/$selectedIconType" + } + val resourceGroup = ResourceGroup( + "drawable", + "revanced_extended_settings_key_icon.xml" + ) - try { - context.copyResources(iconPath, resourceGroup) - } catch (_: Exception) { - // Ignore if resource copy fails + try { + context.copyResources(iconPath, resourceGroup) + } catch (_: Exception) { + // Ignore if resource copy fails - // Add a fallback extended icon - // It's needed if someone provides custom path to icon(s) folder - // but custom branding icons for Extended setting are predefined, - // so it won't copy custom branding icon - // and will raise an error without fallback icon - context.copyResources(fallbackIconPath, resourceGroup) - } - } + // Add a fallback extended icon + // It's needed if someone provides custom path to icon(s) folder + // but custom branding icons for Extended setting are predefined, + // so it won't copy custom branding icon + // and will raise an error without fallback icon + context.copyResources(fallbackIconPath, resourceGroup) } // endregion. diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt index 992e87210..618451dcb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt @@ -12,6 +12,7 @@ import app.revanced.util.ResourceGroup import app.revanced.util.copyResources import app.revanced.util.copyXmlNode import app.revanced.util.doRecursively +import app.revanced.util.lowerCaseOrThrow import app.revanced.util.patch.BaseResourcePatch import org.w3c.dom.Element @@ -37,27 +38,24 @@ object OverlayButtonsPatch : BaseResourcePatch( private const val DEFAULT_MARGIN = "0.0dip" private const val WIDER_MARGIN = "6.0dip" - private const val DEFAULT_ICON_KEY = "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" - ) + private const val DEFAULT_ICON = "bold" // Option to select icon type - private val IconType by stringPatchOption( + private val IconType = stringPatchOption( key = "IconType", - default = DEFAULT_ICON_KEY, - values = iconTypes, + default = DEFAULT_ICON, + values = mapOf( + "Bold" to DEFAULT_ICON, + "Rounded" to "rounded", + "Thin" to "thin" + ), title = "Icon type", description = "The icon type.", required = true ) // Option to set bottom margin - private val BottomMargin by stringPatchOption( + private val BottomMargin = stringPatchOption( key = "BottomMargin", default = DEFAULT_MARGIN, values = mapOf( @@ -76,6 +74,13 @@ object OverlayButtonsPatch : BaseResourcePatch( */ override fun execute(context: ResourceContext) { + // Check patch options first. + val iconType = IconType + .lowerCaseOrThrow() + + val marginBottom = BottomMargin + .lowerCaseOrThrow() + // Inject hooks for overlay buttons. arrayOf( "AlwaysRepeat;", @@ -101,41 +106,38 @@ object OverlayButtonsPatch : BaseResourcePatch( context.copyResources("youtube/overlaybuttons/shared", resourceGroup) } - // Apply the selected icon type to the overlay buttons - IconType?.let { iconType -> - val iconValue = iconType.lowercase() - val commonResources = arrayOf( - "ic_fullscreen_vertical_button.png", - "ic_vr.png", - "quantum_ic_fullscreen_exit_grey600_24.png", - "quantum_ic_fullscreen_exit_white_24.png", - "quantum_ic_fullscreen_grey600_24.png", - "quantum_ic_fullscreen_white_24.png", - "revanced_time_ordered_playlist_icon.png", - "revanced_copy_icon.png", - "revanced_copy_icon_with_time.png", - "revanced_download_icon.png", - "revanced_speed_icon.png", - "revanced_whitelist_icon.png", - "yt_fill_arrow_repeat_white_24.png", - "yt_outline_arrow_repeat_1_white_24.png", - "yt_outline_arrow_shuffle_1_white_24.png", - "yt_outline_screen_full_exit_white_24.png", - "yt_outline_screen_full_white_24.png" + // Apply the selected icon type to the overlay buttons. + val commonResources = arrayOf( + "ic_fullscreen_vertical_button.png", + "ic_vr.png", + "quantum_ic_fullscreen_exit_grey600_24.png", + "quantum_ic_fullscreen_exit_white_24.png", + "quantum_ic_fullscreen_grey600_24.png", + "quantum_ic_fullscreen_white_24.png", + "revanced_time_ordered_playlist_icon.png", + "revanced_copy_icon.png", + "revanced_copy_icon_with_time.png", + "revanced_download_icon.png", + "revanced_speed_icon.png", + "revanced_whitelist_icon.png", + "yt_fill_arrow_repeat_white_24.png", + "yt_outline_arrow_repeat_1_white_24.png", + "yt_outline_arrow_shuffle_1_white_24.png", + "yt_outline_screen_full_exit_white_24.png", + "yt_outline_screen_full_white_24.png" + ) + val specificResources = if (iconType == "thin") { + arrayOf("yt_outline_screen_vertical_vd_theme_24.xml") + } else { + arrayOf("yt_outline_screen_vertical_vd_theme_24.png") + } + val resources = commonResources + specificResources + resources.forEach { resource -> + val folderName = if (resource.endsWith(".xml")) "drawable" else "drawable-xxhdpi" + context.copyResources( + "youtube/overlaybuttons/$iconType", + ResourceGroup(folderName, resource) ) - val specificResources = if (iconValue == "thin") { - arrayOf("yt_outline_screen_vertical_vd_theme_24.xml") - } else { - arrayOf("yt_outline_screen_vertical_vd_theme_24.png") - } - val resources = commonResources + specificResources - resources.forEach { resource -> - val folderName = if (resource.endsWith(".xml")) "drawable" else "drawable-xxhdpi" - context.copyResources( - "youtube/overlaybuttons/$iconValue", - ResourceGroup(folderName, resource) - ) - } } // Merge XML nodes from the host to their respective XML files. @@ -145,9 +147,6 @@ object OverlayButtonsPatch : BaseResourcePatch( "android.support.constraint.ConstraintLayout" ) - val marginBottom = BottomMargin - ?: DEFAULT_MARGIN - // Modify the layout of fullscreen button for newer YouTube versions (19.09.xx+) arrayOf( "youtube_controls_cf_fullscreen_button.xml", diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt index b199b3575..3c0b97e89 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt @@ -18,6 +18,7 @@ import app.revanced.util.copyResources import app.revanced.util.copyXmlNode import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseResourcePatch +import app.revanced.util.valueOrThrow import org.w3c.dom.Element import java.io.Closeable import java.util.concurrent.Executors @@ -38,7 +39,7 @@ object SettingsPatch : BaseResourcePatch( compatiblePackages = COMPATIBLE_PACKAGE, requiresIntegrations = true ), Closeable { - private const val DEFAULT_ELEMENT = "About" + private const val DEFAULT_ELEMENT = "@string/about_key" private const val DEFAULT_NAME = "ReVanced Extended" private val SETTINGS_ELEMENTS_MAP = mapOf( @@ -63,10 +64,10 @@ object SettingsPatch : BaseResourcePatch( "Live chat" to "@string/live_chat_key", "Captions" to "@string/captions_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", default = DEFAULT_ELEMENT, values = SETTINGS_ELEMENTS_MAP, @@ -75,7 +76,7 @@ object SettingsPatch : BaseResourcePatch( required = true ) - private val RVXSettingsMenuName by stringPatchOption( + private val RVXSettingsMenuName = stringPatchOption( key = "RVXSettingsMenuName", default = DEFAULT_NAME, title = "RVX settings menu name", @@ -83,6 +84,8 @@ object SettingsPatch : BaseResourcePatch( required = true ) + private lateinit var customName: String + internal lateinit var contexts: ResourceContext internal var upward1831 = false internal var upward1834 = false @@ -94,6 +97,15 @@ object SettingsPatch : BaseResourcePatch( override fun execute(context: ResourceContext) { + /** + * check patch options + */ + customName = RVXSettingsMenuName + .valueOrThrow() + + val insertKey = InsertPosition + .valueOrThrow() + /** * set resource context */ @@ -148,16 +160,10 @@ object SettingsPatch : BaseResourcePatch( /** * initialize ReVanced Extended Settings */ - val elementKey = SETTINGS_ELEMENTS_MAP[InsertPosition] - ?: InsertPosition - ?: SETTINGS_ELEMENTS_MAP[DEFAULT_ELEMENT] - - elementKey?.let { insertKey -> - context.addPreferenceFragment( - "revanced_extended_settings", - insertKey - ) - } + context.addPreferenceFragment( + "revanced_extended_settings", + insertKey + ) /** * remove ReVanced Extended Settings divider @@ -220,29 +226,26 @@ object SettingsPatch : BaseResourcePatch( * change RVX settings menu name * since it must be invoked after the Translations patch, it must be the last in the order. */ - RVXSettingsMenuName?.let { customName -> - if (customName != DEFAULT_NAME) { - contexts.removeStringsElements( - arrayOf("revanced_extended_settings_title") - ) - contexts.xmlEditor["res/values/strings.xml"].use { editor -> - val document = editor.file + if (customName != DEFAULT_NAME) { + contexts.removeStringsElements( + arrayOf("revanced_extended_settings_title") + ) + contexts.xmlEditor["res/values/strings.xml"].use { editor -> + val document = editor.file - mapOf( - "revanced_extended_settings_title" to customName - ).forEach { (k, v) -> - val stringElement = document.createElement("string") + mapOf( + "revanced_extended_settings_title" to customName + ).forEach { (k, v) -> + val stringElement = document.createElement("string") - stringElement.setAttribute("name", k) - stringElement.textContent = v + stringElement.setAttribute("name", k) + stringElement.textContent = v - document.getElementsByTagName("resources").item(0) - .appendChild(stringElement) - } + document.getElementsByTagName("resources").item(0) + .appendChild(stringElement) } } - } ?: println("WARNING: Invalid RVX settings menu name. RVX settings menu name does not change.") - + } } private fun setVersionInfo() { diff --git a/src/main/kotlin/app/revanced/util/ResourceUtils.kt b/src/main/kotlin/app/revanced/util/ResourceUtils.kt index b4a391876..2592a7519 100644 --- a/src/main/kotlin/app/revanced/util/ResourceUtils.kt +++ b/src/main/kotlin/app/revanced/util/ResourceUtils.kt @@ -3,15 +3,27 @@ package app.revanced.util 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 org.w3c.dom.Element import org.w3c.dom.Node +import java.io.File import java.io.InputStream import java.nio.file.Files import java.nio.file.StandardCopyOption val classLoader: ClassLoader = object {}.javaClass.classLoader +fun PatchOption.valueOrThrow() = value + ?: throw PatchException("Invalid patch option: $title.") + +fun PatchOption.lowerCaseOrThrow() = valueOrThrow() + .lowercase() + +fun PatchOption.underBarOrThrow() = lowerCaseOrThrow() + .replace(" ", "_") + fun Node.adoptChild(tagName: String, block: Element.() -> Unit) { val child = ownerDocument.createElement(tagName) child.block() @@ -48,6 +60,36 @@ fun String.startsWithAny(vararg prefixes: String): Boolean { return false } +fun ResourceContext.copyFile( + resourceGroup: List, + 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. *