feat: merge patch RVX/anddea (#55)

* feat(YouTube): Add `Custom Shorts action buttons` patch (Replaces `Shorts outline icon` patch)

* feat(YouTube): Add `Visual preferences icons` patch

* feat(Custom branding icon): Add more icons

* feat(Custom branding icon): Add patch options `ChangeHeader`, `ChangeSplashIcon`, `RestoreOldSplashAnimation`

* feat(Translations): Add patch options to remove languages and provide own translation / strings.xml

* feat(YouTube/Settings): Add search bar in settings

* feat(YouTube/Shorts components): Add `Hide disabled comments button` and `Hide live chat header` settings

* refactor(YouTube/Settings): Fix typos in strings

* feat(YouTube/Settings): clarify patch option descriptions

Co-authored-by: KobeW50 <84587632+KobeW50@users.noreply.github.com>

* feat(YouTube): clarify patch option

Co-authored-by: KobeW50 <84587632+KobeW50@users.noreply.github.com>

---------

Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com>
Co-authored-by: KobeW50 <84587632+KobeW50@users.noreply.github.com>
This commit is contained in:
Aaron Veil
2024-06-08 18:04:23 +03:00
committed by GitHub
parent ecd6fbdf5b
commit 09ed1b965d
816 changed files with 36893 additions and 499 deletions

View File

@ -2,6 +2,7 @@ package app.revanced.patches.music.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.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.util.ResourceGroup
@ -19,26 +20,79 @@ object CustomBrandingIconPatch : BaseResourcePatch(
private const val DEFAULT_ICON_KEY = "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 Red" to "revancify_red"
"Revancify Red" to "revancify_red",
"YouTube Music" to "youtube_music"
)
private val mipmapIconResourceFileNames = arrayOf(
"adaptiveproduct_youtube_music_background_color_108",
"adaptiveproduct_youtube_music_foreground_color_108",
"ic_launcher_release"
).map { "$it.png" }.toTypedArray()
private val mipmapDirectories = arrayOf(
private val sizeArray = arrayOf(
"xxxhdpi",
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi"
).map { "mipmap-$it" }
)
private var AppIcon by stringPatchOption(
private val largeSizeArray = arrayOf(
"xlarge-hdpi",
"xlarge-mdpi",
"large-xhdpi",
"large-hdpi",
"large-mdpi",
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi",
)
private val drawableDirectories = sizeArray.map { "drawable-$it" }
private val largeDrawableDirectories = largeSizeArray.map { "drawable-$it" }
private val mipmapDirectories = sizeArray.map { "mipmap-$it" }
private val headerIconResourceFileNames = arrayOf(
"action_bar_logo",
"logo_music",
"ytm_logo"
).map { "$it.png" }.toTypedArray()
private val launcherIconResourceFileNames = arrayOf(
"adaptiveproduct_youtube_music_background_color_108",
"adaptiveproduct_youtube_music_foreground_color_108",
"ic_launcher_release"
).map { "$it.png" }.toTypedArray()
private val splashIconResourceFileNames = arrayOf(
// This file only exists in [drawable-hdpi]
// Since {@code ResourceUtils#copyResources} checks for null values before copying,
// Just adds it to the array.
"action_bar_logo_release",
"record"
).map { "$it.png" }.toTypedArray()
private val headerIconResourceGroups = drawableDirectories.map { directory ->
ResourceGroup(
directory, *headerIconResourceFileNames
)
}
private val launcherIconResourceGroups = mipmapDirectories.map { directory ->
ResourceGroup(
directory, *launcherIconResourceFileNames
)
}
private val splashIconResourceGroups = largeDrawableDirectories.map { directory ->
ResourceGroup(
directory, *splashIconResourceFileNames
)
}
private val AppIcon by stringPatchOption(
key = "AppIcon",
default = DEFAULT_ICON_KEY,
values = availableIcon,
@ -50,22 +104,35 @@ object CustomBrandingIconPatch : BaseResourcePatch(
Each of these folders has to have the following files:
${mipmapIconResourceFileNames.joinToString("\n") { "- $it" }}
${launcherIconResourceFileNames.joinToString("\n") { "- $it" }}
"""
.split("\n")
.joinToString("\n") { it.trimIndent() } // Remove the leading whitespace from each line.
.trimIndent(), // Remove the leading newline.
)
private val ChangeHeader by booleanPatchOption(
key = "ChangeHeader",
default = false,
title = "Change header",
description = "Apply the custom branding icon to the header."
)
private val ChangeSplashIcon by booleanPatchOption(
key = "ChangeSplashIcon",
default = true,
title = "Change splash icons",
description = "Apply the custom branding icon to the splash screen."
)
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)) {
mipmapDirectories.map { directory ->
ResourceGroup(
directory, *mipmapIconResourceFileNames
)
}.let { resourceGroups ->
launcherIconResourceGroups.let { resourceGroups ->
try {
val path = File(appIcon)
val resourceDirectory = context["res"]
@ -82,33 +149,47 @@ object CustomBrandingIconPatch : BaseResourcePatch(
}
}
} catch (_: Exception) {
// Exception is thrown if an invalid path is used in the patch option.
throw PatchException("Invalid app icon path: $appIcon")
}
}
} else {
val resourcePath = "music/branding/$appIconValue"
// change launcher icon.
mipmapDirectories.map { directory ->
ResourceGroup(
directory, *mipmapIconResourceFileNames
)
}.let { resourceGroups ->
// Change launcher icon.
launcherIconResourceGroups.let { resourceGroups ->
resourceGroups.forEach {
context.copyResources("$resourcePath/launcher", it)
context.copyResources("$appIconResourcePath/launcher", it)
}
}
// change monochrome icon.
// Change monochrome icon.
arrayOf(
ResourceGroup(
"drawable",
"ic_app_icons_themed_youtube_music.xml"
)
).forEach { resourceGroup ->
context.copyResources("$resourcePath/monochrome", 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)
}
}
}
}
} ?: throw PatchException("Invalid app icon path.")
}
}
}

View File

@ -20,24 +20,26 @@ object CustomBrandingNamePatch : BaseResourcePatch(
key = "AppNameNotification",
default = APP_NAME_LAUNCHER,
values = mapOf(
"Full name" to APP_NAME_NOTIFICATION,
"Short name" to APP_NAME_LAUNCHER
"ReVanced Extended Music" to APP_NAME_NOTIFICATION,
"RVX Music" to APP_NAME_LAUNCHER,
"YouTube Music" to "YouTube Music",
"YT Music" to "YT Music",
),
title = "App name in notification panel",
description = "The name of the app as it appears in the notification panel.",
required = true
)
private val AppNameLauncher by stringPatchOption(
key = "AppNameLauncher",
default = APP_NAME_LAUNCHER,
values = mapOf(
"Full name" to APP_NAME_NOTIFICATION,
"Short name" to APP_NAME_LAUNCHER
"ReVanced Extended Music" to APP_NAME_NOTIFICATION,
"RVX Music" to APP_NAME_LAUNCHER,
"YouTube Music" to "YouTube Music",
"YT Music" to "YT Music",
),
title = "App name in launcher",
description = "The name of the app as it appears in the launcher.",
required = true
)
override fun execute(context: ResourceContext) {
@ -64,7 +66,7 @@ object CustomBrandingNamePatch : BaseResourcePatch(
.appendChild(stringElement)
}
}
} ?: throw PatchException("Invalid app name.")
} ?: throw PatchException("Invalid app name.")
} ?: throw PatchException("Invalid launcher name.")
} ?: throw PatchException("Invalid notification name.")
}
}

View File

@ -0,0 +1,60 @@
package app.revanced.patches.music.layout.translations
import app.revanced.patcher.data.ResourceContext
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.settings.SettingsPatch
import app.revanced.patches.shared.translations.APP_LANGUAGES
import app.revanced.patches.shared.translations.TranslationsUtils.invoke
import app.revanced.util.patch.BaseResourcePatch
@Suppress("unused")
object TranslationsPatch : BaseResourcePatch(
name = "Translations YouTube Music",
description = "Add translations or remove string resources.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE
) {
// Array of supported translations, each represented by its language code.
private val TRANSLATIONS = arrayOf(
"bg-rBG", "bn", "cs-rCZ", "el-rGR", "es-rES", "fr-rFR", "hu-rHU", "id-rID", "in", "it-rIT",
"ja-rJP", "ko-rKR", "nl-rNL", "pl-rPL", "pt-rBR", "ro-rRO", "ru-rRU", "tr-rTR", "uk-rUA",
"vi-rVN", "zh-rCN", "zh-rTW"
)
private var CustomTranslations by stringPatchOption(
key = "CustomTranslations",
default = "",
title = "Custom translations",
description = """
The path to the 'strings.xml' file.
Please note that applying the 'strings.xml' file will overwrite all existing language translations.
""".trimIndent()
)
private var SelectedTranslations by stringPatchOption(
key = "SelectedTranslations",
default = TRANSLATIONS.joinToString(", "),
title = "Translations to add",
description = "A list of translations to be added for the RVX settings, separated by commas."
)
private var SelectedStringResources by stringPatchOption(
key = "SelectedStringResources",
default = APP_LANGUAGES.joinToString(", "),
title = "String resources to keep",
description = """
A list of string resources to be kept, separated by commas.
String resources not in the list will be removed from the app.
Default string resource, English, is not removed.
""".trimIndent()
)
override fun execute(context: ResourceContext) {
context.invoke(
CustomTranslations, SelectedTranslations, SelectedStringResources,
TRANSLATIONS, "music"
)
}
}

View File

@ -1,46 +0,0 @@
package app.revanced.patches.music.misc.translations
import app.revanced.patcher.data.ResourceContext
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.shared.translations.TranslationsUtils.copyXml
import app.revanced.util.patch.BaseResourcePatch
@Suppress("unused")
object TranslationsPatch : BaseResourcePatch(
name = "Translations",
description = "Adds Crowdin translations for YouTube Music.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE
) {
override fun execute(context: ResourceContext) {
context.copyXml(
"music",
arrayOf(
"bg-rBG",
"bn",
"cs-rCZ",
"el-rGR",
"es-rES",
"fr-rFR",
"hu-rHU",
"id-rID",
"in",
"it-rIT",
"ja-rJP",
"ko-rKR",
"nl-rNL",
"pl-rPL",
"pt-rBR",
"ro-rRO",
"ru-rRU",
"tr-rTR",
"uk-rUA",
"vi-rVN",
"zh-rCN",
"zh-rTW"
)
)
}
}

View File

@ -26,24 +26,80 @@ object SettingsPatch : BaseResourcePatch(
compatiblePackages = COMPATIBLE_PACKAGE,
requiresIntegrations = true
), Closeable {
private val THREAD_COUNT = Runtime.getRuntime().availableProcessors()
private val threadPoolExecutor = Executors.newFixedThreadPool(THREAD_COUNT)
lateinit var contexts: ResourceContext
internal var upward0636 = false
internal var upward0642 = false
override fun execute(context: ResourceContext) {
/**
* set resource context
*/
contexts = context
val resourceXmlFile = context["res/values/integers.xml"].readBytes()
/**
* set version info
*/
setVersionInfo()
for (threadIndex in 0 until THREAD_COUNT) {
/**
* copy strings
*/
context.copyXmlNode("music/settings/host", "values/strings.xml", "resources")
/**
* hide divider
*/
val styleFile = context["res/values/styles.xml"]
styleFile.writeText(
styleFile.readText()
.replace(
"allowDividerAbove\">true",
"allowDividerAbove\">false"
).replace(
"allowDividerBelow\">true",
"allowDividerBelow\">false"
)
)
/**
* Copy arrays
*/
contexts.copyXmlNode("music/settings/host", "values/arrays.xml", "resources")
/**
* Copy colors
*/
context.xmlEditor["res/values/colors.xml"].use { editor ->
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
for (i in 0 until resourcesNode.childNodes.length) {
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
node.textContent = when (node.getAttribute("name")) {
"material_deep_teal_500" -> "@android:color/white"
else -> continue
}
}
}
context.addRVXSettingsPreference()
}
private fun setVersionInfo() {
val threadCount = Runtime.getRuntime().availableProcessors()
val threadPoolExecutor = Executors.newFixedThreadPool(threadCount)
val resourceXmlFile = contexts["res/values/integers.xml"].readBytes()
for (threadIndex in 0 until threadCount) {
threadPoolExecutor.execute thread@{
context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
contexts.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
val resources = editor.file.documentElement.childNodes
val resourcesLength = resources.length
val jobSize = resourcesLength / THREAD_COUNT
val jobSize = resourcesLength / threadCount
val batchStart = jobSize * threadIndex
val batchEnd = jobSize * (threadIndex + 1)
@ -71,47 +127,6 @@ object SettingsPatch : BaseResourcePatch(
threadPoolExecutor
.also { it.shutdown() }
.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
/**
* copy strings
*/
context.copyXmlNode("music/settings/host", "values/strings.xml", "resources")
/**
* hide divider
*/
val styleFile = context["res/values/styles.xml"]
styleFile.writeText(
styleFile.readText()
.replace(
"allowDividerAbove\">true",
"allowDividerAbove\">false"
).replace(
"allowDividerBelow\">true",
"allowDividerBelow\">false"
)
)
/**
* Copy colors
*/
context.xmlEditor["res/values/colors.xml"].use { editor ->
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
for (i in 0 until resourcesNode.childNodes.length) {
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
node.textContent = when (node.getAttribute("name")) {
"material_deep_teal_500" -> "@android:color/white"
else -> continue
}
}
}
context.addRVXSettingsPreference()
}
internal fun addSwitchPreference(
@ -162,11 +177,6 @@ object SettingsPatch : BaseResourcePatch(
}
override fun close() {
/**
* Copy arrays
*/
contexts.copyXmlNode("music/settings/host", "values/arrays.xml", "resources")
addPreferenceWithIntent(
CategoryType.MISC,
"revanced_extended_settings_import_export"

View File

@ -32,7 +32,7 @@ object CustomBrandingNamePatch : BaseResourcePatch(
val appName = if (AppName != null) {
AppName!!
} else {
println("WARNING: Invalid name name. Does not apply patches.")
println("WARNING: Invalid app name. Does not apply patches.")
ORIGINAL_APP_NAME
}

View File

@ -2,7 +2,7 @@ package app.revanced.patches.shared.elements
import app.revanced.patcher.data.ResourceContext
@Suppress("DEPRECATION")
@Suppress("DEPRECATION", "unused")
object StringsElementsUtils {
internal fun ResourceContext.removeStringsElements(

View File

@ -1,28 +1,172 @@
package app.revanced.patches.shared.translations
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.util.inputStreamFromBundledResource
import org.w3c.dom.Node
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
@Suppress("DEPRECATION")
object TranslationsUtils {
internal fun ResourceContext.copyXml(
internal fun ResourceContext.invoke(
customTranslations: String?,
selectedTranslations: String?,
selectedStringResources: String?,
translationsArray: Array<String>,
sourceDirectory: String
) {
// Check if the custom translation path is valid.
customTranslations?.takeIf { it.isNotEmpty() }?.let { customLang ->
try {
val customLangFile = File(customLang)
if (!customLangFile.exists() || !customLangFile.isFile || customLangFile.name != "strings.xml") {
throw PatchException("Invalid custom language file: $customLang")
}
val resourceDirectory = this["res"].resolve("values")
val destinationFile = resourceDirectory.resolve("strings.xml")
updateStringsXml(customLangFile, destinationFile)
} catch (e: Exception) {
// Exception is thrown if an invalid path is used in the patch option.
throw PatchException("Invalid custom translations path: $customLang")
}
}?: run {
// Process selected translations if no custom translation is set.
val selectedTranslationsArray =
selectedTranslations?.split(",")?.map { it.trim() }?.toTypedArray()
?: throw PatchException("Invalid selected languages.")
val filteredLanguages = translationsArray.filter { it in selectedTranslationsArray }.toTypedArray()
copyXml(sourceDirectory, filteredLanguages)
}
// Process selected string resources.
val selectedStringResourcesArray =
selectedStringResources?.split(",")?.map { it.trim() }?.toTypedArray()
?: throw PatchException("Invalid selected string resources.")
val filteredStringResources =
APP_LANGUAGES.filter { it in selectedStringResourcesArray }.toTypedArray()
val resourceDirectory = this["res"]
// Remove unselected app languages.
APP_LANGUAGES.filter { it !in filteredStringResources }.forEach { language ->
resourceDirectory.resolve("values-$language").takeIf { it.exists() && it.isDirectory }
?.deleteRecursively()
}
}
/**
* Extension function to ResourceContext to copy XML translation files.
*
* @param sourceDirectory The source directory containing the translation files.
* @param languageArray The array of language codes to process.
*/
private fun ResourceContext.copyXml(
sourceDirectory: String,
languageArray: Array<String>
) {
languageArray.forEach { language ->
val directory = "values-$language-v21"
this["res/$directory"].mkdir()
inputStreamFromBundledResource(
"$sourceDirectory/translations",
"$language/strings.xml"
)?.let { inputStream ->
val directory = "values-$language-v21"
val valuesV21Directory = this["res"].resolve(directory)
if (!valuesV21Directory.isDirectory) Files.createDirectories(valuesV21Directory.toPath())
Files.copy(
inputStreamFromBundledResource(
"$sourceDirectory/translations",
"$language/strings.xml"
)!!,
this["res"].resolve("$directory/strings.xml").toPath(),
StandardCopyOption.REPLACE_EXISTING
)
Files.copy(
inputStream,
this["res"].resolve("$directory/strings.xml").toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
}
/**
* Updates the contents of the destination strings.xml file by merging it with the source strings.xml file.
*
* This function reads both source and destination XML files, compares each <string> element by their
* unique "name" attribute, and if a match is found, it replaces the content in the destination file with
* the content from the source file.
*
* @param sourceFile The source strings.xml file containing new string values.
* @param destinationFile The destination strings.xml file to be updated with values from the source file.
*/
private fun updateStringsXml(sourceFile: File, destinationFile: File) {
val documentBuilderFactory = DocumentBuilderFactory.newInstance()
val documentBuilder = documentBuilderFactory.newDocumentBuilder()
// Parse the source and destination XML files into Document objects
val sourceDoc = documentBuilder.parse(sourceFile)
val destinationDoc = documentBuilder.parse(destinationFile)
val sourceStrings = sourceDoc.getElementsByTagName("string")
val destinationStrings = destinationDoc.getElementsByTagName("string")
// Create a map to store the <string> elements from the source document by their "name" attribute
val sourceMap = mutableMapOf<String, Node>()
// Populate the map with nodes from the source document
for (i in 0 until sourceStrings.length) {
val node = sourceStrings.item(i)
val name = node.attributes.getNamedItem("name").nodeValue
sourceMap[name] = node
}
// Update the destination document with values from the source document
for (i in 0 until destinationStrings.length) {
val node = destinationStrings.item(i)
val name = node.attributes.getNamedItem("name").nodeValue
if (sourceMap.containsKey(name)) {
node.textContent = sourceMap[name]?.textContent
}
}
/**
* Prepare the transformer for writing the updated document back to the file.
* The transformer is configured to indent the output XML for better readability.
*/
val transformerFactory = TransformerFactory.newInstance()
val transformer = transformerFactory.newTransformer()
transformer.setOutputProperty(OutputKeys.INDENT, "yes")
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
val domSource = DOMSource(destinationDoc)
val streamResult = StreamResult(destinationFile)
transformer.transform(domSource, streamResult)
}
}
// Array of all possible app languages.
val APP_LANGUAGES = arrayOf(
"af", "am", "ar", "ar-rXB", "as", "az",
"b+es+419", "b+sr+Latn", "be", "bg", "bn", "bs",
"ca", "cs",
"da", "de",
"el", "en-rAU", "en-rCA", "en-rGB", "en-rIN", "en-rXA", "en-rXC", "es", "es-rUS", "et", "eu",
"fa", "fi", "fr", "fr-rCA",
"gl", "gu",
"hi", "hr", "hu", "hy",
"id", "in", "is", "it", "iw",
"ja",
"ka", "kk", "km", "kn", "ko", "ky",
"lo", "lt", "lv",
"mk", "ml", "mn", "mr", "ms", "my",
"nb", "ne", "nl", "no",
"or",
"pa", "pl", "pt", "pt-rBR", "pt-rPT",
"ro", "ru",
"si", "sk", "sl", "sq", "sr", "sv", "sw",
"ta", "te", "th", "tl", "tr",
"uk", "ur", "uz",
"vi",
"zh", "zh-rCN", "zh-rHK", "zh-rTW", "zu",
)

View File

@ -0,0 +1,84 @@
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.patch.BaseResourcePatch
@Suppress("unused")
object ShortsActionButtonsPatch : BaseResourcePatch(
name = "Custom Shorts action buttons",
description = "Changes, at compile time, the icon of the action buttons of the Shorts player.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE
) {
private const val DEFAULT_ICON_KEY = "Round"
private val IconType by stringPatchOption(
key = "IconType",
default = DEFAULT_ICON_KEY,
values = mapOf(
"Outline" to "outline",
"OutlineCircle" to "outlinecircle",
DEFAULT_ICON_KEY to "round"
),
title = "Shorts icon style ",
description = "The style of the icons for the action buttons in the Shorts player."
)
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",
// 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.")
SettingsPatch.updatePatchStatus(this)
}
}

View File

@ -21,7 +21,7 @@ object AnimatedLikePatch : BaseResourcePatch(
* Copy json
*/
context.copyResources(
"youtube/animated",
"youtube/shorts/animated",
ResourceGroup(
"raw",
"like_tap_feedback.json"

View File

@ -2,12 +2,14 @@ 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
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusIcon
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup
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
@ -17,47 +19,84 @@ 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
compatiblePackages = COMPATIBLE_PACKAGE,
) {
private const val DEFAULT_ICON_KEY = "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 Red" to "revancify_red"
"Revancify Red" to "revancify_red",
"YouTube" to "youtube"
)
private val drawableIconResourceFileNames = arrayOf(
"product_logo_youtube_color_24",
"product_logo_youtube_color_36",
"product_logo_youtube_color_144",
"product_logo_youtube_color_192"
).map { "$it.png" }.toTypedArray()
private val drawableDirectories = arrayOf(
private val sizeArray = arrayOf(
"xxxhdpi",
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi"
).map { "drawable-$it" }
)
private val mipmapIconResourceFileNames = arrayOf(
private val drawableDirectories = sizeArray.map { "drawable-$it" }
private val mipmapDirectories = sizeArray.map { "mipmap-$it" }
private val headerIconResourceFileNames = arrayOf(
"yt_premium_wordmark_header_dark",
"yt_premium_wordmark_header_light",
"yt_wordmark_header_dark",
"yt_wordmark_header_light"
).map { "$it.png" }.toTypedArray()
private val launcherIconResourceFileNames = arrayOf(
"adaptiveproduct_youtube_background_color_108",
"adaptiveproduct_youtube_foreground_color_108",
"ic_launcher",
"ic_launcher_round"
).map { "$it.png" }.toTypedArray()
private val mipmapDirectories = arrayOf(
"xxxhdpi",
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi"
).map { "mipmap-$it" }
private val splashIconResourceFileNames = arrayOf(
"product_logo_youtube_color_24",
"product_logo_youtube_color_36",
"product_logo_youtube_color_144",
"product_logo_youtube_color_192"
).map { "$it.png" }.toTypedArray()
private var AppIcon by stringPatchOption(
private val oldSplashAnimationResourceFileNames = arrayOf(
"\$\$avd_anim__1__0",
"\$\$avd_anim__1__1",
"\$\$avd_anim__2__0",
"\$\$avd_anim__2__1",
"\$\$avd_anim__3__0",
"\$\$avd_anim__3__1",
"\$avd_anim__0",
"\$avd_anim__1",
"\$avd_anim__2",
"\$avd_anim__3",
"\$avd_anim__4",
"avd_anim"
).map { "$it.xml" }.toTypedArray()
private fun List<String>.getResourceGroup(fileNames: Array<String>) = map { directory ->
ResourceGroup(
directory, *fileNames
)
}
private val headerIconResourceGroups = drawableDirectories.getResourceGroup(headerIconResourceFileNames)
private val launcherIconResourceGroups = mipmapDirectories.getResourceGroup(launcherIconResourceFileNames)
private val splashIconResourceGroups = drawableDirectories.getResourceGroup(splashIconResourceFileNames)
private val oldSplashAnimationResourceGroups = listOf("drawable").getResourceGroup(oldSplashAnimationResourceFileNames)
// region patch option
val AppIcon by stringPatchOption(
key = "AppIcon",
default = DEFAULT_ICON_KEY,
values = availableIcon,
@ -69,22 +108,45 @@ object CustomBrandingIconPatch : BaseResourcePatch(
Each of these folders has to have the following files:
${mipmapIconResourceFileNames.joinToString("\n") { "- $it" }}
${launcherIconResourceFileNames.joinToString("\n") { "- $it" }}
"""
.split("\n")
.joinToString("\n") { it.trimIndent() } // Remove the leading whitespace from each line.
.trimIndent(), // Remove the leading newline.
)
private val ChangeHeader by booleanPatchOption(
key = "ChangeHeader",
default = false,
title = "Change header",
description = "Apply the custom branding icon to the header."
)
private val ChangeSplashIcon by booleanPatchOption(
key = "ChangeSplashIcon",
default = true,
title = "Change splash icons",
description = "Apply the custom branding icon to the splash screen."
)
private val RestoreOldSplashAnimation by booleanPatchOption(
key = "RestoreOldSplashAnimation",
default = false,
title = "Restore old splash animation",
description = "Restores old style splash animation."
)
// 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)) {
mipmapDirectories.map { directory ->
ResourceGroup(
directory, *mipmapIconResourceFileNames
)
}.let { resourceGroups ->
launcherIconResourceGroups.let { resourceGroups ->
try {
val path = File(appIcon)
val resourceDirectory = context["res"]
@ -100,48 +162,63 @@ object CustomBrandingIconPatch : BaseResourcePatch(
)
}
}
context.updatePatchStatusIcon("custom")
} catch (_: Exception) {
// Exception is thrown if an invalid path is used in the patch option.
throw PatchException("Invalid app icon path: $appIcon")
}
}
} else {
val resourcePath = "youtube/branding/$appIconValue"
// change launcher icon.
mipmapDirectories.map { directory ->
ResourceGroup(
directory, *mipmapIconResourceFileNames
)
}.let { resourceGroups ->
// Change launcher icon.
launcherIconResourceGroups.let { resourceGroups ->
resourceGroups.forEach {
context.copyResources("$resourcePath/launcher", it)
context.copyResources("$appIconResourcePath/launcher", it)
}
}
// change splash icon.
drawableDirectories.map { directory ->
ResourceGroup(
directory, *drawableIconResourceFileNames
)
}.let { resourceGroups ->
resourceGroups.forEach {
context.copyResources("$resourcePath/splash", it)
}
}
// change monochrome icon.
// Change monochrome icon.
arrayOf(
ResourceGroup(
"drawable",
"adaptive_monochrome_ic_youtube_launcher.xml"
)
).forEach { resourceGroup ->
context.copyResources("$resourcePath/monochrome", 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)
}
}
}
// 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.")
}
}
}

View File

@ -22,12 +22,13 @@ object CustomBrandingNamePatch : BaseResourcePatch(
key = "AppName",
default = APP_NAME,
values = mapOf(
"Full name" to "ReVanced Extended",
"Short name" to APP_NAME
"ReVanced Extended" to "ReVanced Extended",
"RVX" to APP_NAME,
"YouTube RVX" to "YouTube RVX",
"YouTube" to "YouTube",
),
title = "App name",
description = "The name of the app.",
required = true
description = "The name of the app."
)
override fun execute(context: ResourceContext) {

View File

@ -1,42 +1,61 @@
package app.revanced.patches.youtube.layout.translations
import app.revanced.patcher.data.ResourceContext
import app.revanced.patches.shared.translations.TranslationsUtils.copyXml
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.shared.translations.APP_LANGUAGES
import app.revanced.patches.shared.translations.TranslationsUtils.invoke
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.patch.BaseResourcePatch
@Suppress("unused")
object TranslationsPatch : BaseResourcePatch(
name = "Translations",
description = "Adds Crowdin translations for YouTube.",
name = "Translations YouTube",
description = "Add translations or remove string resources.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE
) {
override fun execute(context: ResourceContext) {
// Array of supported translations, each represented by its language code.
private val TRANSLATIONS = arrayOf(
"ar", "el-rGR", "es-rES", "fr-rFR", "hu-rHU", "it-rIT", "ja-rJP", "ko-rKR", "pl-rPL",
"pt-rBR", "ru-rRU", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
)
context.copyXml(
"youtube",
arrayOf(
"ar",
"el-rGR",
"es-rES",
"fr-rFR",
"hu-rHU",
"it-rIT",
"ja-rJP",
"ko-rKR",
"pl-rPL",
"pt-rBR",
"ru-rRU",
"tr-rTR",
"uk-rUA",
"vi-rVN",
"zh-rCN",
"zh-rTW"
)
private var CustomTranslations by stringPatchOption(
key = "CustomTranslations",
default = "",
title = "Custom translations",
description = """
The path to the 'strings.xml' file.
Please note that applying the 'strings.xml' file will overwrite all existing translations.
""".trimIndent()
)
private var SelectedTranslations by stringPatchOption(
key = "SelectedTranslations",
default = TRANSLATIONS.joinToString(", "),
title = "Translations to add",
description = "A list of translations to be added for the RVX settings, separated by commas."
)
private var SelectedStringResources by stringPatchOption(
key = "SelectedStringResources",
default = APP_LANGUAGES.joinToString(", "),
title = "String resources to keep",
description = """
A list of string resources to be kept, separated by commas.
String resources not in the list will be removed from the app.
Default string resource, English, is not removed.
""".trimIndent()
)
override fun execute(context: ResourceContext) {
context.invoke(
CustomTranslations, SelectedTranslations, SelectedStringResources,
TRANSLATIONS, "youtube"
)
SettingsPatch.updatePatchStatus(this)
SettingsPatch.updatePatchStatus("Translations")
}
}

View File

@ -0,0 +1,377 @@
package app.revanced.patches.youtube.layout.visual
import app.revanced.patcher.data.ResourceContext
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
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.doRecursively
import app.revanced.util.patch.BaseResourcePatch
import org.w3c.dom.Element
@Suppress("DEPRECATION", "unused")
object VisualPreferencesIconsPatch : BaseResourcePatch(
name = "Visual preferences icons",
description = "Adds icons to specific preferences in the settings.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE,
use = false
) {
private const val DEFAULT_ICON_KEY = "Extension"
private val RVXSettingsMenuIcon by stringPatchOption(
key = "RVXSettingsMenuIcon",
default = DEFAULT_ICON_KEY,
values = mapOf(
"Custom branding icon" to "custom_branding_icon",
DEFAULT_ICON_KEY to "extension",
"Gear" to "gear",
"ReVanced" to "revanced",
"ReVanced Colored" to "revanced_colored",
),
title = "RVX settings menu icon",
description = "Apply different icons for RVX settings menu."
)
override fun execute(context: ResourceContext) {
// region copy shared resources.
arrayOf(
ResourceGroup(
"drawable",
*preferenceIcon.values.map { "$it.xml" }.toTypedArray()
),
ResourceGroup(
"drawable-xxhdpi",
"$emptyIcon.png"
),
).forEach { resourceGroup ->
context.copyResources("youtube/visual/shared", resourceGroup)
}
// endregion.
// 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"
)
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)
}
}
}
// endregion.
// region set visual preferences icon.
arrayOf(
"res/xml/revanced_prefs.xml",
"res/xml/settings_fragment.xml"
).forEach { xmlFile ->
context.xmlEditor[xmlFile].use { editor ->
editor.file.doRecursively loop@{ node ->
if (node !is Element) return@loop
node.getAttributeNode("android:key")
?.textContent
?.removePrefix("@string/")
?.let { title ->
val drawableName = when (title) {
in preferenceKey -> preferenceIcon[title]
// Add custom RVX settings menu icon
in intentKey -> intentIcon[title]
in emptyTitles -> emptyIcon
else -> null
}
drawableName?.let {
node.setAttribute("android:icon", "@drawable/$it")
}
}
}
}
}
// endregion.
SettingsPatch.updatePatchStatus(this)
}
// region preference key and icon.
private val preferenceKey = setOf(
// Main settings (sorted as displayed in the settings)
"parent_tools_key",
"general_key",
"account_switcher_key",
"data_saving_settings_key",
"auto_play_key",
"video_quality_settings_key",
"offline_key",
"pair_with_tv_key",
"history_key",
"your_data_key",
"privacy_key",
"premium_early_access_browse_page_key",
"subscription_product_setting_key",
"billing_and_payment_key",
"notification_key",
"connected_accounts_browse_page_key",
"live_chat_key",
"captions_key",
"accessibility_settings_key",
"about_key",
// Main RVX settings (sorted as displayed in the settings)
"revanced_preference_screen_ads",
"revanced_preference_screen_alt_thumbnails",
"revanced_preference_screen_feed",
"revanced_preference_screen_general",
"revanced_preference_screen_player",
"revanced_preference_screen_shorts",
"revanced_preference_screen_swipe_controls",
"revanced_preference_screen_video",
"revanced_preference_screen_ryd",
"revanced_preference_screen_sb",
"revanced_preference_screen_misc",
// Internal RVX settings (items without prefix are listed first, others are sorted alphabetically)
"gms_core_settings",
"sb_enable_create_segment",
"sb_enable_voting",
"revanced_alt_thumbnail_home",
"revanced_alt_thumbnail_library",
"revanced_alt_thumbnail_player",
"revanced_alt_thumbnail_search",
"revanced_alt_thumbnail_subscriptions",
"revanced_change_shorts_repeat_state",
"revanced_custom_player_overlay_opacity",
"revanced_default_app_settings",
"revanced_default_playback_speed",
"revanced_default_video_quality_wifi",
"revanced_disable_hdr_auto_brightness",
"revanced_disable_hdr_video",
"revanced_disable_quic_protocol",
"revanced_enable_debug_logging",
"revanced_enable_default_playback_speed_shorts",
"revanced_enable_external_browser",
"revanced_enable_old_quality_layout",
"revanced_enable_open_links_directly",
"revanced_enable_swipe_brightness",
"revanced_enable_swipe_haptic_feedback",
"revanced_enable_swipe_lowest_value_auto_brightness",
"revanced_enable_swipe_press_to_engage",
"revanced_enable_swipe_volume",
"revanced_enable_watch_panel_gestures",
"revanced_hide_clip_button",
"revanced_hide_download_button",
"revanced_hide_keyword_content_comments",
"revanced_hide_keyword_content_home",
"revanced_hide_keyword_content_search",
"revanced_hide_keyword_content_subscriptions",
"revanced_hide_like_dislike_button",
"revanced_hide_navigation_create_button",
"revanced_hide_navigation_home_button",
"revanced_hide_navigation_library_button",
"revanced_hide_navigation_notifications_button",
"revanced_hide_navigation_shorts_button",
"revanced_hide_navigation_subscriptions_button",
"revanced_hide_player_autoplay_button",
"revanced_hide_player_captions_button",
"revanced_hide_player_cast_button",
"revanced_hide_player_collapse_button",
"revanced_hide_player_flyout_menu_ambient_mode",
"revanced_hide_player_flyout_menu_audio_track",
"revanced_hide_player_flyout_menu_captions",
"revanced_hide_player_flyout_menu_help",
"revanced_hide_player_flyout_menu_lock_screen",
"revanced_hide_player_flyout_menu_loop_video",
"revanced_hide_player_flyout_menu_more_info",
"revanced_hide_player_flyout_menu_playback_speed",
"revanced_hide_player_flyout_menu_quality_footer",
"revanced_hide_player_flyout_menu_report",
"revanced_hide_player_flyout_menu_stable_volume",
"revanced_hide_player_flyout_menu_stats_for_nerds",
"revanced_hide_player_flyout_menu_watch_in_vr",
"revanced_hide_player_fullscreen_button",
"revanced_hide_player_previous_next_button",
"revanced_hide_player_youtube_music_button",
"revanced_hide_playlist_button",
"revanced_hide_quick_actions_comment_button",
"revanced_hide_quick_actions_dislike_button",
"revanced_hide_quick_actions_like_button",
"revanced_hide_quick_actions_live_chat_button",
"revanced_hide_quick_actions_more_button",
"revanced_hide_quick_actions_save_to_playlist_button",
"revanced_hide_quick_actions_share_button",
"revanced_hide_remix_button",
"revanced_hide_report_button",
"revanced_hide_share_button",
"revanced_hide_shorts_comments_button",
"revanced_hide_shorts_dislike_button",
"revanced_hide_shorts_like_button",
"revanced_hide_shorts_navigation_bar",
"revanced_hide_shorts_remix_button",
"revanced_hide_shorts_share_button",
"revanced_hide_shorts_shelf_history",
"revanced_hide_shorts_shelf_home_related_videos",
"revanced_hide_shorts_shelf_search",
"revanced_hide_shorts_shelf_subscriptions",
"revanced_hide_shorts_toolbar",
"revanced_overlay_button_always_repeat",
"revanced_overlay_button_copy_video_url",
"revanced_overlay_button_copy_video_url_timestamp",
"revanced_overlay_button_external_downloader",
"revanced_overlay_button_speed_dialog",
"revanced_overlay_button_time_ordered_playlist",
"revanced_overlay_button_whitelist",
"revanced_preference_screen_account_menu",
"revanced_preference_screen_action_buttons",
"revanced_preference_screen_ambient_mode",
"revanced_preference_screen_category_bar",
"revanced_preference_screen_channel_bar",
"revanced_preference_screen_channel_profile",
"revanced_preference_screen_comments",
"revanced_preference_screen_community_posts",
"revanced_preference_screen_custom_filter",
"revanced_preference_screen_feed_flyout_menu",
"revanced_preference_screen_fullscreen",
"revanced_preference_screen_haptic_feedback",
"revanced_preference_screen_import_export",
"revanced_preference_screen_navigation_buttons",
"revanced_preference_screen_patch_information",
"revanced_preference_screen_player_buttons",
"revanced_preference_screen_player_flyout_menu",
"revanced_preference_screen_seekbar",
"revanced_preference_screen_settings_menu",
"revanced_preference_screen_shorts_player",
"revanced_preference_screen_spoof_client",
"revanced_preference_screen_toolbar",
"revanced_preference_screen_video_description",
"revanced_preference_screen_video_filter",
"revanced_sanitize_sharing_links",
"revanced_swipe_gestures_lock_mode",
"revanced_swipe_magnitude_threshold",
"revanced_swipe_overlay_background_alpha",
"revanced_swipe_overlay_rect_size",
"revanced_swipe_overlay_text_size",
"revanced_swipe_overlay_timeout",
"revanced_switch_create_with_notifications_button",
"revanced_change_player_flyout_menu_toggle",
)
private val intentKey = setOf(
"revanced_extended_settings_key",
)
private val emptyTitles = setOf(
"revanced_custom_playback_speeds",
"revanced_custom_playback_speed_menu_type",
"revanced_default_video_quality_mobile",
"revanced_disable_default_playback_speed_live",
"revanced_enable_custom_playback_speed",
"revanced_external_downloader_package_name",
"revanced_hide_shorts_comments_disabled_button",
"revanced_hide_player_flyout_menu_captions_footer",
"revanced_remember_playback_speed_last_selected",
"revanced_remember_video_quality_last_selected",
"revanced_restore_old_video_quality_menu",
"revanced_enable_debug_buffer_logging",
"revanced_whitelist_settings",
)
// A lot of mappings here.
// The performance impact should be negligible in this context,
// as the operations involved are not computationally intensive.
private val preferenceIcon = preferenceKey.associateWith { title ->
when (title) {
// Main RVX settings
"revanced_preference_screen_general" -> "general_key_icon"
"revanced_preference_screen_sb" -> "sb_enable_create_segment_icon"
// Internal RVX settings
"revanced_alt_thumbnail_home" -> "revanced_hide_navigation_home_button_icon"
"revanced_alt_thumbnail_library" -> "revanced_preference_screen_video_icon"
"revanced_alt_thumbnail_player" -> "revanced_preference_screen_player_icon"
"revanced_alt_thumbnail_search" -> "revanced_hide_shorts_shelf_search_icon"
"revanced_alt_thumbnail_subscriptions" -> "revanced_hide_navigation_subscriptions_button_icon"
"revanced_custom_player_overlay_opacity" -> "revanced_swipe_overlay_background_alpha_icon"
"revanced_default_app_settings" -> "revanced_preference_screen_settings_menu_icon"
"revanced_default_playback_speed" -> "revanced_overlay_button_speed_dialog_icon"
"revanced_enable_old_quality_layout" -> "revanced_default_video_quality_wifi_icon"
"revanced_enable_watch_panel_gestures" -> "revanced_preference_screen_swipe_controls_icon"
"revanced_hide_download_button" -> "revanced_overlay_button_external_downloader_icon"
"revanced_hide_keyword_content_comments" -> "revanced_hide_quick_actions_comment_button_icon"
"revanced_hide_keyword_content_home" -> "revanced_hide_navigation_home_button_icon"
"revanced_hide_keyword_content_search" -> "revanced_hide_shorts_shelf_search_icon"
"revanced_hide_keyword_content_subscriptions" -> "revanced_hide_navigation_subscriptions_button_icon"
"revanced_hide_like_dislike_button" -> "sb_enable_voting_icon"
"revanced_hide_navigation_library_button" -> "revanced_preference_screen_video_icon"
"revanced_hide_navigation_notifications_button" -> "notification_key_icon"
"revanced_hide_navigation_shorts_button" -> "revanced_preference_screen_shorts_icon"
"revanced_hide_player_autoplay_button" -> "revanced_change_player_flyout_menu_toggle_icon"
"revanced_hide_player_captions_button" -> "captions_key_icon"
"revanced_hide_player_flyout_menu_ambient_mode" -> "revanced_preference_screen_ambient_mode_icon"
"revanced_hide_player_flyout_menu_captions" -> "captions_key_icon"
"revanced_hide_player_flyout_menu_loop_video" -> "revanced_overlay_button_always_repeat_icon"
"revanced_hide_player_flyout_menu_more_info" -> "about_key_icon"
"revanced_hide_player_flyout_menu_quality_footer" -> "revanced_default_video_quality_wifi_icon"
"revanced_hide_player_flyout_menu_report" -> "revanced_hide_report_button_icon"
"revanced_hide_player_fullscreen_button" -> "revanced_preference_screen_fullscreen_icon"
"revanced_hide_quick_actions_dislike_button" -> "revanced_preference_screen_ryd_icon"
"revanced_hide_quick_actions_live_chat_button" -> "live_chat_key_icon"
"revanced_hide_quick_actions_save_to_playlist_button" -> "revanced_hide_playlist_button_icon"
"revanced_hide_quick_actions_share_button" -> "revanced_hide_shorts_share_button_icon"
"revanced_hide_remix_button" -> "revanced_hide_shorts_remix_button_icon"
"revanced_hide_share_button" -> "revanced_hide_shorts_share_button_icon"
"revanced_hide_shorts_comments_button" -> "revanced_hide_quick_actions_comment_button_icon"
"revanced_hide_shorts_dislike_button" -> "revanced_preference_screen_ryd_icon"
"revanced_hide_shorts_like_button" -> "revanced_hide_quick_actions_like_button_icon"
"revanced_hide_shorts_navigation_bar" -> "revanced_preference_screen_navigation_buttons_icon"
"revanced_hide_shorts_shelf_home_related_videos" -> "revanced_hide_navigation_home_button_icon"
"revanced_hide_shorts_shelf_subscriptions" -> "revanced_hide_navigation_subscriptions_button_icon"
"revanced_hide_shorts_toolbar" -> "revanced_preference_screen_toolbar_icon"
"revanced_preference_screen_account_menu" -> "account_switcher_key_icon"
"revanced_preference_screen_channel_bar" -> "account_switcher_key_icon"
"revanced_preference_screen_channel_profile" -> "account_switcher_key_icon"
"revanced_preference_screen_comments" -> "revanced_hide_quick_actions_comment_button_icon"
"revanced_preference_screen_feed_flyout_menu" -> "revanced_preference_screen_player_flyout_menu_icon"
"revanced_preference_screen_haptic_feedback" -> "revanced_enable_swipe_haptic_feedback_icon"
"revanced_preference_screen_patch_information" -> "about_key_icon"
"revanced_preference_screen_shorts_player" -> "revanced_preference_screen_shorts_icon"
"revanced_preference_screen_video_filter" -> "revanced_preference_screen_video_icon"
"revanced_swipe_gestures_lock_mode" -> "revanced_hide_player_flyout_menu_lock_screen_icon"
"revanced_disable_hdr_auto_brightness" -> "revanced_disable_hdr_video_icon"
else -> "${title}_icon"
}
}
private val intentIcon = intentKey.associateWith { "${it}_icon" }
private const val emptyIcon = "empty_icon"
// endregion.
}

View File

@ -299,12 +299,14 @@ object ShortsComponentPatch : BaseBytecodePatch(
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE_SCREEN: SHORTS",
"SETTINGS: SHORTS_COMPONENTS"
)
var settingArray = arrayOf(
"PREFERENCE_SCREEN: SHORTS",
"SETTINGS: SHORTS_COMPONENTS"
)
if (SettingsPatch.upward1834) {
settingArray += "SETTINGS: HIDE_SHORTS_COMMENTS_DISABLED_BUTTON"
}
SettingsPatch.addPreference(settingArray)
SettingsPatch.updatePatchStatus(this)
}

View File

@ -1,60 +0,0 @@
package app.revanced.patches.youtube.shorts.outlinebutton
import app.revanced.patcher.data.ResourceContext
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.patch.BaseResourcePatch
@Suppress("unused")
object ShortsOutlineButtonPatch : BaseResourcePatch(
name = "Shorts outline button",
description = "Applies, at compile time, the outline icon to the action buttons in the Shorts player.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE
) {
override fun execute(context: ResourceContext) {
arrayOf(
"xxxhdpi",
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi"
).forEach { dpi ->
context.copyResources(
"youtube/shorts/outline",
ResourceGroup(
"drawable-$dpi",
"ic_remix_filled_white_24.webp",
"ic_remix_filled_white_shadowed.webp",
"ic_right_comment_shadowed.webp",
"ic_right_dislike_off_shadowed.webp",
"ic_right_dislike_on_32c.webp",
"ic_right_dislike_on_shadowed.webp",
"ic_right_like_off_shadowed.webp",
"ic_right_like_on_32c.webp",
"ic_right_like_on_shadowed.webp",
"ic_right_share_shadowed.webp"
)
)
}
arrayOf(
// Shorts outline icons for older versions of YouTube
ResourceGroup(
"drawable",
"ic_right_comment_32c.xml",
"ic_right_dislike_off_32c.xml",
"ic_right_like_off_32c.xml",
"ic_right_share_32c.xml"
)
).forEach { resourceGroup ->
context.copyResources("youtube/shorts/outline", resourceGroup)
}
SettingsPatch.updatePatchStatus(this)
}
}

View File

@ -152,7 +152,7 @@ object SwipeControlsPatch : BaseBytecodePatch(
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE_CATEGORY: SWIPE_CONTROLS_EXPERIMENTAL_FLAGS",
"SETTINGS: ENABLE_WATCH_PANEL_GESTEURES"
"SETTINGS: ENABLE_WATCH_PANEL_GESTURES"
)
)
} ?: println("WARNING: Failed to resolve WatchPanelGesturesFingerprint")

View File

@ -100,18 +100,33 @@ object ResourceUtils {
}
}
fun ResourceContext.addPreferenceFragment(key: String) {
fun ResourceContext.addPreferenceFragment(key: String, insertKey: String) {
val targetClass =
"com.google.android.apps.youtube.app.settings.videoquality.VideoQualitySettingsActivity"
this.xmlEditor[YOUTUBE_SETTINGS_PATH].use { editor ->
with(editor.file) {
doRecursively loop@{
if (it !is Element) return@loop
it.getAttributeNode("android:key")?.let { attribute ->
if (attribute.textContent == "@string/about_key" && it.getAttributeNode("app:iconSpaceReserved").textContent == "false") {
it.insertNode("Preference", it) {
setAttribute("android:title", "@string/" + key + "_title")
val processedKeys = mutableSetOf<String>() // To track processed keys
doRecursively loop@{ node ->
if (node !is Element) return@loop // Skip if not an element
val attributeNode = node.getAttributeNode("android:key")
?: return@loop // Skip if no key attribute
val currentKey = attributeNode.textContent
// Check if the current key has already been processed
if (processedKeys.contains(currentKey)) {
return@loop // Skip if already processed
} else {
processedKeys.add(currentKey) // Add the current key to processedKeys
}
when (currentKey) {
insertKey -> {
node.insertNode("Preference", node) {
setAttribute("android:key", "${key}_key")
setAttribute("android:title", "@string/${key}_title")
this.appendChild(
ownerDocument.createElement("intent").also { intentNode ->
intentNode.setAttribute(
@ -120,24 +135,18 @@ object ResourceUtils {
)
intentNode.setAttribute("android:data", key + "_intent")
intentNode.setAttribute("android:targetClass", targetClass)
})
}
)
}
it.getAttributeNode("app:iconSpaceReserved").textContent = "true"
return@loop
node.setAttribute("app:iconSpaceReserved", "true")
}
}
}
doRecursively loop@{
if (it !is Element) return@loop
it.getAttributeNode("app:iconSpaceReserved")?.let { attribute ->
if (attribute.textContent == "true") {
attribute.textContent = "false"
"true" -> {
attributeNode.textContent = "false"
}
}
}
}
}
}
}
}

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.utils.settings
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.shared.elements.StringsElementsUtils.removeStringsElements
import app.revanced.patches.shared.mapping.ResourceMappingPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
@ -37,9 +38,48 @@ object SettingsPatch : BaseResourcePatch(
compatiblePackages = COMPATIBLE_PACKAGE,
requiresIntegrations = true
), Closeable {
private const val DEFAULT_ELEMENT = "About"
private const val DEFAULT_NAME = "ReVanced Extended"
private val THREAD_COUNT = Runtime.getRuntime().availableProcessors()
private val threadPoolExecutor = Executors.newFixedThreadPool(THREAD_COUNT)
private val SETTINGS_ELEMENTS_MAP = mapOf(
"Parent settings" to "@string/parent_tools_key",
"General" to "@string/general_key",
"Account" to "@string/account_switcher_key",
"Data saving" to "@string/data_saving_settings_key",
"Autoplay" to "@string/auto_play_key",
"Video quality preferences" to "@string/video_quality_settings_key",
"Background" to "@string/offline_key",
"Watch on TV" to "@string/pair_with_tv_key",
"Manage all history" to "@string/history_key",
"Your data in YouTube" to "@string/your_data_key",
"Privacy" to "@string/privacy_key",
"History & privacy" to "@string/privacy_key",
"Try experimental new features" to "@string/premium_early_access_browse_page_key",
"Purchases and memberships" to "@string/subscription_product_setting_key",
"Billing & payments" to "@string/billing_and_payment_key",
"Billing and payments" to "@string/billing_and_payment_key",
"Notifications" to "@string/notification_key",
"Connected apps" to "@string/connected_accounts_browse_page_key",
"Live chat" to "@string/live_chat_key",
"Captions" to "@string/captions_key",
"Accessibility" to "@string/accessibility_settings_key",
DEFAULT_ELEMENT to "@string/about_key"
)
private val InsertPosition by stringPatchOption(
key = "InsertPosition",
default = DEFAULT_ELEMENT,
values = SETTINGS_ELEMENTS_MAP,
title = "Insert position",
description = "The settings menu name that the RVX settings menu should be above."
)
private val RVXSettingsMenuName by stringPatchOption(
key = "RVXSettingsMenuName",
default = DEFAULT_NAME,
title = "RVX settings menu name",
description = "The name of the RVX settings menu."
)
internal lateinit var contexts: ResourceContext
internal var upward1831 = false
@ -51,48 +91,16 @@ object SettingsPatch : BaseResourcePatch(
internal var upward1912 = false
override fun execute(context: ResourceContext) {
/**
* set resource context
*/
contexts = context
val resourceXmlFile = context["res/values/integers.xml"].readBytes()
for (threadIndex in 0 until THREAD_COUNT) {
threadPoolExecutor.execute thread@{
context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
val resources = editor.file.documentElement.childNodes
val resourcesLength = resources.length
val jobSize = resourcesLength / THREAD_COUNT
val batchStart = jobSize * threadIndex
val batchEnd = jobSize * (threadIndex + 1)
element@ for (i in batchStart until batchEnd) {
if (i >= resourcesLength) return@thread
val node = resources.item(i)
if (node !is Element) continue
if (node.nodeName != "integer" || !node.getAttribute("name")
.startsWith("google_play_services_version")
) continue
val playServicesVersion = node.textContent.toInt()
upward1831 = 233200000 <= playServicesVersion
upward1834 = 233500000 <= playServicesVersion
upward1839 = 234000000 <= playServicesVersion
upward1842 = 234302000 <= playServicesVersion
upward1849 = 235000000 <= playServicesVersion
upward1902 = 240204000 < playServicesVersion
upward1912 = 241302000 <= playServicesVersion
break
}
}
}
}
threadPoolExecutor
.also { it.shutdown() }
.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
/**
* set version info
*/
setVersionInfo()
/**
* remove strings duplicated with RVX resources
@ -138,7 +146,16 @@ object SettingsPatch : BaseResourcePatch(
/**
* initialize ReVanced Extended Settings
*/
context.addPreferenceFragment("revanced_extended_settings")
val elementKey = SETTINGS_ELEMENTS_MAP[InsertPosition]
?: InsertPosition
?: SETTINGS_ELEMENTS_MAP[DEFAULT_ELEMENT]
elementKey?.let { insertKey ->
context.addPreferenceFragment(
"revanced_extended_settings",
insertKey
)
}
/**
* remove ReVanced Extended Settings divider
@ -164,6 +181,112 @@ object SettingsPatch : BaseResourcePatch(
}
}
/**
* set revanced-patches version
*/
val jarManifest = classLoader.getResources("META-INF/MANIFEST.MF")
while (jarManifest.hasMoreElements())
contexts.updatePatchStatusSettings(
"ReVanced Patches",
Manifest(jarManifest.nextElement().openStream())
.mainAttributes
.getValue("Version") + ""
)
/**
* set revanced-integrations version
*/
val versionName = SettingsBytecodePatch.contexts
.findClass { it.sourceFile == "BuildConfig.java" }!!
.mutableClass
.fields
.single { it.name == "VERSION_NAME" }
.initialValue
.toString()
.trim()
.replace("\"", "")
.replace("&quot;", "")
contexts.updatePatchStatusSettings(
"ReVanced Integrations",
versionName
)
}
override fun close() {
/**
* 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
mapOf(
"revanced_extended_settings_title" to customName
).forEach { (k, v) ->
val stringElement = document.createElement("string")
stringElement.setAttribute("name", k)
stringElement.textContent = v
document.getElementsByTagName("resources").item(0)
.appendChild(stringElement)
}
}
}
} ?: println("WARNING: Invalid RVX settings menu name. RVX settings menu name does not change.")
}
private fun setVersionInfo() {
val threadCount = Runtime.getRuntime().availableProcessors()
val threadPoolExecutor = Executors.newFixedThreadPool(threadCount)
val resourceXmlFile = contexts["res/values/integers.xml"].readBytes()
for (threadIndex in 0 until threadCount) {
threadPoolExecutor.execute thread@{
contexts.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
val resources = editor.file.documentElement.childNodes
val resourcesLength = resources.length
val jobSize = resourcesLength / threadCount
val batchStart = jobSize * threadIndex
val batchEnd = jobSize * (threadIndex + 1)
element@ for (i in batchStart until batchEnd) {
if (i >= resourcesLength) return@thread
val node = resources.item(i)
if (node !is Element) continue
if (node.nodeName != "integer" || !node.getAttribute("name")
.startsWith("google_play_services_version")
) continue
val playServicesVersion = node.textContent.toInt()
upward1831 = 233200000 <= playServicesVersion
upward1834 = 233500000 <= playServicesVersion
upward1839 = 234000000 <= playServicesVersion
upward1842 = 234302000 <= playServicesVersion
upward1849 = 235000000 <= playServicesVersion
upward1902 = 240204000 < playServicesVersion
upward1912 = 241302000 <= playServicesVersion
break
}
}
}
}
threadPoolExecutor
.also { it.shutdown() }
.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
}
internal fun addPreference(settingArray: Array<String>) {
@ -178,39 +301,7 @@ object SettingsPatch : BaseResourcePatch(
updatePatchStatus(patch.name!!)
}
internal fun updatePatchStatus(patchTitle: String) {
contexts.updatePatchStatus(patchTitle)
internal fun updatePatchStatus(patchName: String) {
contexts.updatePatchStatus(patchName)
}
override fun close() {
// region set ReVanced Patches Version
val jarManifest = classLoader.getResources("META-INF/MANIFEST.MF")
while (jarManifest.hasMoreElements())
contexts.updatePatchStatusSettings(
"ReVanced Patches",
Manifest(jarManifest.nextElement().openStream())
.mainAttributes
.getValue("Version") + ""
)
// endregion
// region set ReVanced Integrations Version
val buildConfigMutableClass =
SettingsBytecodePatch.contexts.findClass { it.sourceFile == "BuildConfig.java" }!!.mutableClass
val versionNameField = buildConfigMutableClass.fields.single { it.name == "VERSION_NAME" }
val versionName =
versionNameField.initialValue.toString().trim().replace("\"", "").replace("&quot;", "")
contexts.updatePatchStatusSettings(
"ReVanced Integrations",
versionName
)
// endregion
}
}
}

View File

@ -63,11 +63,14 @@ fun ResourceContext.copyResources(
for (resourceGroup in resources) {
resourceGroup.resources.forEach { resource ->
val resourceFile = "${resourceGroup.resourceDirectoryName}/$resource"
Files.copy(
inputStreamFromBundledResource(sourceResourceDirectory, resourceFile)!!,
targetResourceDirectory.resolve(resourceFile).toPath(),
StandardCopyOption.REPLACE_EXISTING,
)
inputStreamFromBundledResource(sourceResourceDirectory, resourceFile)?.let { inputStream ->
Files.copy(
inputStream,
targetResourceDirectory.resolve(resourceFile).toPath(),
StandardCopyOption.REPLACE_EXISTING,
)
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,788 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108.0dp"
android:height="108.0dp"
android:viewportWidth="108.0"
android:viewportHeight="108.0">
<path
android:pathData="M0,0h108zM0,1h108zM0,2h108zM0,3h108zM0,4h108zM0,5h108zM0,6h108zM0,7h108zM0,8h108zM0,9h108zM0,10h108zM0,11h108zM0,12h108zM0,13h108zM0,14h108zM0,15h108zM0,16h108zM0,17h108zM0,18h108zM0,19h108zM0,20h108zM0,21h108zM0,22h108zM0,23h108zM0,24h108zM0,25h108zM0,26h108zM0,27h108zM0,28h108zM0,29h108zM0,30h108zM0,31h108zM0,32h108zM0,33h108zM0,34h108zM0,35h108zM0,36h53zM60,36h48zM0,37h48zM64,37h44zM0,38h47zM65,38h43zM0,39h45zM67,39h41zM0,40h44zM69,40h39zM0,41h34zM39,41h4zM69,41h39zM0,42h33zM41,42h1zM70,42h38zM0,43h33zM71,43h37zM0,44h32zM72,44h36zM0,45h32zM72,45h36zM0,46h32zM42,46h2zM73,46h35zM0,47h32zM41,47h4zM54,47h4zM73,47h35zM0,48h32zM41,48h6zM51,48h10zM74,48h34zM0,49h32zM41,49h6zM53,49h9zM74,49h34zM0,50h32zM40,50h7zM55,50h8zM74,50h34zM0,51h32zM40,51h7zM56,51h7zM75,51h33zM0,52h32zM39,52h7zM57,52h6zM75,52h33zM0,53h32zM39,53h7zM57,53h7zM75,53h33zM0,54h32zM39,54h7zM58,54h6zM75,54h33zM0,55h32zM39,55h7zM58,55h6zM75,55h33zM0,56h32zM39,56h7zM57,56h6zM75,56h33zM0,57h32zM40,57h7zM57,57h6zM75,57h33zM0,58h32zM40,58h7zM56,58h7zM74,58h34zM0,59h32zM41,59h6zM53,59h9zM74,59h34zM0,60h32zM41,60h7zM52,60h9zM74,60h34zM0,61h32zM41,61h4zM53,61h6zM73,61h35zM0,62h32zM41,62h3zM55,62h1zM73,62h35zM0,63h32zM73,63h35zM0,64h32zM72,64h36zM0,65h33zM72,65h36zM0,66h33zM71,66h37zM0,67h34zM39,67h3zM70,67h38zM0,68h35zM38,68h5zM69,68h39zM0,69h45zM68,69h40zM0,70h47zM66,70h42zM0,71h48zM64,71h44zM0,72h51zM61,72h47zM0,73h108zM0,74h108zM0,75h108zM0,76h108zM0,77h108zM0,78h108zM0,79h108zM0,80h108zM0,81h108zM0,82h108zM0,83h108zM0,84h108zM0,85h108zM0,86h108zM0,87h108zM0,88h108zM0,89h108zM0,90h108zM0,91h108zM0,92h108zM0,93h108zM0,94h108zM0,95h108zM0,96h108zM0,97h108zM0,98h108zM0,99h108zM0,100h108zM0,101h108zM0,102h108zM0,103h108zM0,104h108zM0,105h108zM0,106h108zM0,107h108z"
android:strokeColor="#00000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,36h1zM73,48h1zM47,50h1zM54,50h1zM74,52h1zM74,53h1zM51,60h1z"
android:strokeColor="#05000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,36h1zM57,36h1zM46,54h1zM56,56h1zM47,58h1zM52,72h1z"
android:strokeColor="#09000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,36h1zM55,46h1zM52,47h1zM54,58h1zM52,59h1zM38,67h1z"
android:strokeColor="#10000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,36h1zM49,37h1zM44,46h1zM40,48h1zM71,64h1zM66,69h1zM63,71h1z"
android:strokeColor="#0f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,36h1zM64,38h1zM66,39h1zM33,42h1zM71,44h1zM72,46h1zM47,48h1zM40,49h1zM54,62h1zM36,68h1z"
android:strokeColor="#04000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,36h1zM68,40h1zM34,41h1zM38,41h1zM53,47h1zM58,47h1zM47,49h1zM46,52h1zM57,55h1zM39,57h1zM56,57h1zM45,61h1zM59,61h1zM56,62h1zM72,63h1zM71,65h1zM70,66h1zM42,67h1zM69,67h1zM67,69h1zM65,70h1zM51,72h1z"
android:strokeColor="#01000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,37h1zM63,37h1zM45,39h1zM32,44h1zM41,46h1zM52,49h1zM56,52h1zM63,56h1zM74,57h1zM52,61h1zM57,62h1zM41,66h1z"
android:strokeColor="#03000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,37h1zM39,58h1zM54,72h1z"
android:strokeColor="#29000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,37h1zM50,60h1z"
android:strokeColor="#57000000"
android:strokeWidth="1.0" />
<path
android:pathData="M52,37h1zM43,45h1z"
android:strokeColor="#6f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,37h1zM43,42h1zM52,46h1zM73,52h1zM38,57h1z"
android:strokeColor="#9f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,37h1zM67,41h1z"
android:strokeColor="#b9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,37h1zM35,42h1zM63,49h1zM52,58h1z"
android:strokeColor="#c1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,37h1zM42,44h1zM73,55h1zM68,66h1z"
android:strokeColor="#c2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,37h1zM49,38h1zM63,70h1z"
android:strokeColor="#b8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,37h1z"
android:strokeColor="#98000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,37h1z"
android:strokeColor="#7c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,37h1z"
android:strokeColor="#59000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,37h1zM49,71h1zM57,72h1z"
android:strokeColor="#30000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,37h1zM37,41h1zM60,61h1z"
android:strokeColor="#15000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,38h1zM40,42h1zM45,47h1zM46,53h1zM32,64h1z"
android:strokeColor="#07000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,38h1z"
android:strokeColor="#69000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,38h1zM43,64h1z"
android:strokeColor="#ed000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,38h1zM48,47h1zM39,65h1z"
android:strokeColor="#f6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M52,38h1zM59,38h1zM64,40h1zM69,44h1zM59,45h1zM49,47h1zM48,52h1zM37,55h1zM55,55h1zM54,56h1zM36,66h1zM45,67h1zM50,70h1z"
android:strokeColor="#fb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,38h1zM58,38h1zM35,43h1zM44,43h1zM34,44h1zM39,44h1zM44,44h1zM39,45h1zM46,45h1zM51,45h1zM50,46h1zM62,46h1zM70,47h1zM64,49h1zM71,49h1zM37,51h1zM52,51h1zM37,52h1zM53,52h1zM37,56h1zM53,56h1zM37,57h1zM71,59h1zM70,61h1zM62,62h1zM39,63h1zM34,64h1zM39,64h1zM54,64h1zM56,64h2zM44,65h1zM67,66h1zM66,67h1zM64,68h1zM63,69h1zM52,70h1z"
android:strokeColor="#fe000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,38h4zM49,39h14zM48,40h16zM46,41h20zM45,42h22zM36,43h2zM45,43h23zM35,44h4zM45,44h24zM34,45h5zM47,45h4zM60,45h10zM34,46h5zM48,46h2zM63,46h7zM34,47h5zM63,47h7zM34,48h5zM64,48h7zM34,49h5zM65,49h6zM34,50h4zM65,50h7zM34,51h3zM49,51h3zM65,51h8zM34,52h3zM49,52h4zM65,52h8zM34,53h3zM48,53h7zM66,53h7zM34,54h3zM48,54h7zM66,54h7zM34,55h3zM48,55h7zM66,55h7zM34,56h3zM49,56h4zM65,56h8zM34,57h3zM49,57h4zM65,57h8zM34,58h4zM50,58h1zM65,58h7zM34,59h5zM65,59h6zM34,60h5zM64,60h7zM34,61h5zM63,61h7zM34,62h5zM48,62h2zM63,62h7zM34,63h5zM47,63h4zM61,63h9zM35,64h4zM45,64h9zM55,64h1zM58,64h11zM35,65h4zM45,65h23zM45,66h22zM46,67h20zM48,68h16zM48,69h15zM53,70h7z"
android:strokeColor="#ff000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,38h1zM47,40h1zM66,41h1zM43,44h1zM39,46h1zM64,50h1zM65,53h1zM60,63h1zM40,64h1z"
android:strokeColor="#fa000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,38h1zM49,59h1zM39,61h1zM59,63h1z"
android:strokeColor="#ec000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,38h1z"
android:strokeColor="#c5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,38h1zM39,59h1zM65,69h1z"
android:strokeColor="#6d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M46,39h1zM39,42h1zM64,70h1z"
android:strokeColor="#2e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,39h1zM42,43h1z"
android:strokeColor="#86000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,39h1zM63,39h1zM45,45h1zM62,61h1zM37,66h1z"
android:strokeColor="#f1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,39h1zM40,43h1zM33,44h1z"
android:strokeColor="#97000000"
android:strokeWidth="1.0" />
<path
android:pathData="M65,39h1zM55,72h1z"
android:strokeColor="#33000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,40h1zM32,45h1zM59,47h1zM39,51h1zM40,60h1zM32,63h1z"
android:strokeColor="#0a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,40h1z"
android:strokeColor="#80000000"
android:strokeWidth="1.0" />
<path
android:pathData="M46,40h1zM50,47h1zM53,51h1z"
android:strokeColor="#dd000000"
android:strokeWidth="1.0" />
<path
android:pathData="M65,40h1z"
android:strokeColor="#e5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M66,40h1z"
android:strokeColor="#82000000"
android:strokeWidth="1.0" />
<path
android:pathData="M67,40h1z"
android:strokeColor="#1a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M35,41h1zM69,42h1zM48,71h1z"
android:strokeColor="#0e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M36,41h1z"
android:strokeColor="#26000000"
android:strokeWidth="1.0" />
<path
android:pathData="M43,41h1zM46,61h1z"
android:strokeColor="#12000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,41h1z"
android:strokeColor="#8b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,41h1zM72,50h1z"
android:strokeColor="#f3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M68,41h1zM53,50h1z"
android:strokeColor="#22000000"
android:strokeWidth="1.0" />
<path
android:pathData="M34,42h1z"
android:strokeColor="#3e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M36,42h1zM39,43h1zM49,70h1zM54,71h1z"
android:strokeColor="#e3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M37,42h1zM44,67h1z"
android:strokeColor="#cc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,42h1zM64,53h1z"
android:strokeColor="#6e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M42,42h1zM56,46h1zM72,62h1z"
android:strokeColor="#0d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,42h1zM65,55h1zM39,62h1zM61,62h1zM70,63h1z"
android:strokeColor="#f7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M67,42h1zM52,45h1zM70,46h1zM49,50h2zM37,53h1zM71,60h1zM46,63h1zM44,64h1zM43,65h1zM68,65h1zM51,70h1z"
android:strokeColor="#fc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M68,42h1zM72,60h1z"
android:strokeColor="#a2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,43h1zM43,63h1z"
android:strokeColor="#44000000"
android:strokeWidth="1.0" />
<path
android:pathData="M34,43h1zM54,45h1zM46,46h1zM49,49h1z"
android:strokeColor="#dc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,43h1zM40,44h1zM62,47h1zM37,54h1zM72,58h1z"
android:strokeColor="#f9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,43h1zM47,51h1z"
android:strokeColor="#2c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M43,43h1zM68,43h1zM71,48h1zM50,62h1zM65,68h1zM61,70h1z"
android:strokeColor="#f8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M69,43h1zM62,48h1z"
android:strokeColor="#92000000"
android:strokeWidth="1.0" />
<path
android:pathData="M70,43h1zM40,66h1z"
android:strokeColor="#11000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,44h1z"
android:strokeColor="#b5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M70,44h1z"
android:strokeColor="#79000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,45h1zM33,52h1zM33,56h1zM58,63h1z"
android:strokeColor="#c9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,45h1zM51,50h1z"
android:strokeColor="#d7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,45h1zM46,47h1zM45,62h1z"
android:strokeColor="#37000000"
android:strokeWidth="1.0" />
<path
android:pathData="M42,45h1z"
android:strokeColor="#16000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,45h1zM47,54h1z"
android:strokeColor="#b6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,45h1zM34,65h1z"
android:strokeColor="#ee000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,45h1zM33,48h1zM33,60h1zM53,63h1z"
android:strokeColor="#cb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,45h1zM33,51h1zM33,57h1z"
android:strokeColor="#c7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,45h1z"
android:strokeColor="#d1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,45h1zM56,71h1z"
android:strokeColor="#eb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M70,45h1zM48,51h1z"
android:strokeColor="#ea000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,45h1zM70,65h1zM56,72h1z"
android:strokeColor="#36000000"
android:strokeWidth="1.0" />
<path
android:pathData="M32,46h1zM32,47h1zM32,48h1zM32,49h1zM32,50h1zM32,51h1zM32,52h1zM32,53h1zM32,54h1zM74,54h1zM32,55h1zM32,56h1zM32,57h1zM32,58h1zM32,59h1zM62,59h1zM32,60h1zM61,60h1zM32,61h1zM32,62h1zM33,66h1z"
android:strokeColor="#0b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,46h1zM33,49h1zM33,54h1zM48,58h1zM33,59h1zM33,62h1z"
android:strokeColor="#c6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,46h1z"
android:strokeColor="#77000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,46h1zM38,55h1z"
android:strokeColor="#6b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,46h1zM61,46h1zM55,54h1zM48,56h1zM49,58h1zM64,59h1zM70,62h1zM51,63h1zM69,64h1zM44,66h1zM47,68h1zM60,70h1z"
android:strokeColor="#fd000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,46h1zM63,60h1z"
android:strokeColor="#e7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,46h1zM64,54h1z"
android:strokeColor="#4e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,46h1z"
android:strokeColor="#2a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,46h1zM53,62h1z"
android:strokeColor="#1b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,46h1zM63,58h1z"
android:strokeColor="#45000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,46h1z"
android:strokeColor="#95000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,46h1z"
android:strokeColor="#e0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,46h1z"
android:strokeColor="#93000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,47h1zM33,61h1z"
android:strokeColor="#ca000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,47h1zM65,54h1zM51,58h1zM46,68h1z"
android:strokeColor="#f2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,47h1zM55,57h1z"
android:strokeColor="#40000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,47h1z"
android:strokeColor="#a8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,47h1zM68,67h1z"
android:strokeColor="#4c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,47h1zM50,48h1z"
android:strokeColor="#48000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,47h1zM64,69h1z"
android:strokeColor="#df000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,47h1zM53,71h1z"
android:strokeColor="#d4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,47h1zM61,48h1zM73,59h1z"
android:strokeColor="#24000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,48h1zM40,65h1z"
android:strokeColor="#c4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,48h1z"
android:strokeColor="#52000000"
android:strokeWidth="1.0" />
<path
android:pathData="M49,48h1zM64,57h1z"
android:strokeColor="#c3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,48h1zM38,50h1zM53,57h1zM49,61h1z"
android:strokeColor="#f5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,48h1z"
android:strokeColor="#7f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,49h1zM42,64h1z"
android:strokeColor="#88000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,49h1zM67,68h1z"
android:strokeColor="#43000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,49h1zM42,65h1z"
android:strokeColor="#ac000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,49h1z"
android:strokeColor="#25000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,49h1zM51,61h1zM69,66h1z"
android:strokeColor="#1e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,49h1zM33,50h1zM33,58h1z"
android:strokeColor="#ce000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,49h1z"
android:strokeColor="#17000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,50h1zM48,60h1zM43,67h1z"
android:strokeColor="#3d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,50h1zM48,70h1z"
android:strokeColor="#af000000"
android:strokeWidth="1.0" />
<path
android:pathData="M52,50h1zM73,57h1z"
android:strokeColor="#8d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,50h1zM47,61h1z"
android:strokeColor="#5c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,50h1z"
android:strokeColor="#4d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,51h1z"
android:strokeColor="#b2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,51h1z"
android:strokeColor="#75000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,51h1z"
android:strokeColor="#18000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,51h1z"
android:strokeColor="#13000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,51h1z"
android:strokeColor="#d2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,51h1z"
android:strokeColor="#81000000"
android:strokeWidth="1.0" />
<path
android:pathData="M74,51h1zM57,54h1zM46,56h1zM55,58h1zM40,59h1zM47,59h1zM44,62h1zM35,68h1zM37,68h1zM43,68h1zM60,72h1z"
android:strokeColor="#02000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,52h1z"
android:strokeColor="#94000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,52h1zM46,69h1z"
android:strokeColor="#5b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,52h1zM48,57h1zM47,62h1z"
android:strokeColor="#f0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,52h1z"
android:strokeColor="#7d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,52h1zM74,55h1zM74,56h1zM42,63h1zM34,67h1zM68,68h1z"
android:strokeColor="#06000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,52h1zM61,61h1zM54,63h1z"
android:strokeColor="#a1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,53h1zM33,55h1zM33,63h1zM47,69h1z"
android:strokeColor="#cd000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,53h1z"
android:strokeColor="#78000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,53h1z"
android:strokeColor="#9b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,53h1zM64,58h1zM52,63h1z"
android:strokeColor="#f4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,53h1z"
android:strokeColor="#2d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,53h1z"
android:strokeColor="#bf000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,54h1zM33,65h1zM41,65h1z"
android:strokeColor="#61000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,54h1z"
android:strokeColor="#74000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,54h1zM38,66h1z"
android:strokeColor="#ba000000"
android:strokeWidth="1.0" />
<path
android:pathData="M46,55h1z"
android:strokeColor="#08000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,55h1z"
android:strokeColor="#a6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,55h1z"
android:strokeColor="#47000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,55h1z"
android:strokeColor="#63000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,56h1zM64,56h1zM55,63h2z"
android:strokeColor="#90000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,56h1z"
android:strokeColor="#73000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,56h1z"
android:strokeColor="#b0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,56h1zM46,62h1z"
android:strokeColor="#a9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,57h1z"
android:strokeColor="#3a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,57h1z"
android:strokeColor="#ae000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,57h1zM73,60h1zM45,69h1zM59,72h1z"
android:strokeColor="#0c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,58h1zM48,61h1zM67,67h1z"
android:strokeColor="#e4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,58h1z"
android:strokeColor="#49000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,58h1zM34,66h1z"
android:strokeColor="#65000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,59h1z"
android:strokeColor="#5d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,59h1z"
android:strokeColor="#db000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,59h1zM40,62h1zM52,62h1z"
android:strokeColor="#62000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,59h1z"
android:strokeColor="#a0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,59h1z"
android:strokeColor="#e2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,60h1zM71,62h1zM70,64h1z"
android:strokeColor="#b4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M49,60h1z"
android:strokeColor="#b7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,60h1z"
android:strokeColor="#67000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,61h1z"
android:strokeColor="#34000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,61h1z"
android:strokeColor="#b3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,61h1z"
android:strokeColor="#e6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,61h1z"
android:strokeColor="#3c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,62h1zM40,63h1z"
android:strokeColor="#be000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,62h1z"
android:strokeColor="#14000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,62h1z"
android:strokeColor="#4a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,62h1z"
android:strokeColor="#a3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,63h1zM44,68h1z"
android:strokeColor="#20000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,63h1z"
android:strokeColor="#85000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,63h1z"
android:strokeColor="#da000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,63h1z"
android:strokeColor="#9c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,63h1zM50,71h1z"
android:strokeColor="#51000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,64h1zM52,71h1z"
android:strokeColor="#ad000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,64h1z"
android:strokeColor="#9d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M69,65h1z"
android:strokeColor="#bc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M35,66h1zM55,71h1zM57,71h1z"
android:strokeColor="#e8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,66h1z"
android:strokeColor="#58000000"
android:strokeWidth="1.0" />
<path
android:pathData="M42,66h1zM58,72h1z"
android:strokeColor="#1c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M43,66h1z"
android:strokeColor="#c8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M35,67h1z"
android:strokeColor="#4b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M36,67h1z"
android:strokeColor="#84000000"
android:strokeWidth="1.0" />
<path
android:pathData="M37,67h1z"
android:strokeColor="#5a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,68h1z"
android:strokeColor="#aa000000"
android:strokeWidth="1.0" />
<path
android:pathData="M66,68h1z"
android:strokeColor="#b1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,70h1z"
android:strokeColor="#28000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,70h1z"
android:strokeColor="#e9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,71h1z"
android:strokeColor="#8c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,71h1z"
android:strokeColor="#d8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,71h1z"
android:strokeColor="#bb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,71h1z"
android:strokeColor="#8e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,71h1z"
android:strokeColor="#54000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,71h1z"
android:strokeColor="#38000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,72h1z"
android:strokeColor="#19000000"
android:strokeWidth="1.0" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -0,0 +1,788 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108.0dp"
android:height="108.0dp"
android:viewportWidth="108.0"
android:viewportHeight="108.0">
<path
android:pathData="M0,0h108zM0,1h108zM0,2h108zM0,3h108zM0,4h108zM0,5h108zM0,6h108zM0,7h108zM0,8h108zM0,9h108zM0,10h108zM0,11h108zM0,12h108zM0,13h108zM0,14h108zM0,15h108zM0,16h108zM0,17h108zM0,18h108zM0,19h108zM0,20h108zM0,21h108zM0,22h108zM0,23h108zM0,24h108zM0,25h108zM0,26h108zM0,27h108zM0,28h108zM0,29h108zM0,30h108zM0,31h108zM0,32h108zM0,33h108zM0,34h108zM0,35h108zM0,36h53zM60,36h48zM0,37h48zM64,37h44zM0,38h47zM65,38h43zM0,39h45zM67,39h41zM0,40h44zM69,40h39zM0,41h34zM39,41h4zM69,41h39zM0,42h33zM41,42h1zM70,42h38zM0,43h33zM71,43h37zM0,44h32zM72,44h36zM0,45h32zM72,45h36zM0,46h32zM42,46h2zM73,46h35zM0,47h32zM41,47h4zM54,47h4zM73,47h35zM0,48h32zM41,48h6zM51,48h10zM74,48h34zM0,49h32zM41,49h6zM53,49h9zM74,49h34zM0,50h32zM40,50h7zM55,50h8zM74,50h34zM0,51h32zM40,51h7zM56,51h7zM75,51h33zM0,52h32zM39,52h7zM57,52h6zM75,52h33zM0,53h32zM39,53h7zM57,53h7zM75,53h33zM0,54h32zM39,54h7zM58,54h6zM75,54h33zM0,55h32zM39,55h7zM58,55h6zM75,55h33zM0,56h32zM39,56h7zM57,56h6zM75,56h33zM0,57h32zM40,57h7zM57,57h6zM75,57h33zM0,58h32zM40,58h7zM56,58h7zM74,58h34zM0,59h32zM41,59h6zM53,59h9zM74,59h34zM0,60h32zM41,60h7zM52,60h9zM74,60h34zM0,61h32zM41,61h4zM53,61h6zM73,61h35zM0,62h32zM41,62h3zM55,62h1zM73,62h35zM0,63h32zM73,63h35zM0,64h32zM72,64h36zM0,65h33zM72,65h36zM0,66h33zM71,66h37zM0,67h34zM39,67h3zM70,67h38zM0,68h35zM38,68h5zM69,68h39zM0,69h45zM68,69h40zM0,70h47zM66,70h42zM0,71h48zM64,71h44zM0,72h51zM61,72h47zM0,73h108zM0,74h108zM0,75h108zM0,76h108zM0,77h108zM0,78h108zM0,79h108zM0,80h108zM0,81h108zM0,82h108zM0,83h108zM0,84h108zM0,85h108zM0,86h108zM0,87h108zM0,88h108zM0,89h108zM0,90h108zM0,91h108zM0,92h108zM0,93h108zM0,94h108zM0,95h108zM0,96h108zM0,97h108zM0,98h108zM0,99h108zM0,100h108zM0,101h108zM0,102h108zM0,103h108zM0,104h108zM0,105h108zM0,106h108zM0,107h108z"
android:strokeColor="#00000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,36h1zM73,48h1zM47,50h1zM54,50h1zM74,52h1zM74,53h1zM51,60h1z"
android:strokeColor="#05000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,36h1zM57,36h1zM46,54h1zM56,56h1zM47,58h1zM52,72h1z"
android:strokeColor="#09000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,36h1zM55,46h1zM52,47h1zM54,58h1zM52,59h1zM38,67h1z"
android:strokeColor="#10000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,36h1zM49,37h1zM44,46h1zM40,48h1zM71,64h1zM66,69h1zM63,71h1z"
android:strokeColor="#0f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,36h1zM64,38h1zM66,39h1zM33,42h1zM71,44h1zM72,46h1zM47,48h1zM40,49h1zM54,62h1zM36,68h1z"
android:strokeColor="#04000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,36h1zM68,40h1zM34,41h1zM38,41h1zM53,47h1zM58,47h1zM47,49h1zM46,52h1zM57,55h1zM39,57h1zM56,57h1zM45,61h1zM59,61h1zM56,62h1zM72,63h1zM71,65h1zM70,66h1zM42,67h1zM69,67h1zM67,69h1zM65,70h1zM51,72h1z"
android:strokeColor="#01000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,37h1zM63,37h1zM45,39h1zM32,44h1zM41,46h1zM52,49h1zM56,52h1zM63,56h1zM74,57h1zM52,61h1zM57,62h1zM41,66h1z"
android:strokeColor="#03000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,37h1zM39,58h1zM54,72h1z"
android:strokeColor="#29000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,37h1zM50,60h1z"
android:strokeColor="#57000000"
android:strokeWidth="1.0" />
<path
android:pathData="M52,37h1zM43,45h1z"
android:strokeColor="#6f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,37h1zM43,42h1zM52,46h1zM73,52h1zM38,57h1z"
android:strokeColor="#9f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,37h1zM67,41h1z"
android:strokeColor="#b9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,37h1zM35,42h1zM63,49h1zM52,58h1z"
android:strokeColor="#c1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,37h1zM42,44h1zM73,55h1zM68,66h1z"
android:strokeColor="#c2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,37h1zM49,38h1zM63,70h1z"
android:strokeColor="#b8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,37h1z"
android:strokeColor="#98000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,37h1z"
android:strokeColor="#7c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,37h1z"
android:strokeColor="#59000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,37h1zM49,71h1zM57,72h1z"
android:strokeColor="#30000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,37h1zM37,41h1zM60,61h1z"
android:strokeColor="#15000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,38h1zM40,42h1zM45,47h1zM46,53h1zM32,64h1z"
android:strokeColor="#07000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,38h1z"
android:strokeColor="#69000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,38h1zM43,64h1z"
android:strokeColor="#ed000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,38h1zM48,47h1zM39,65h1z"
android:strokeColor="#f6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M52,38h1zM59,38h1zM64,40h1zM69,44h1zM59,45h1zM49,47h1zM48,52h1zM37,55h1zM55,55h1zM54,56h1zM36,66h1zM45,67h1zM50,70h1z"
android:strokeColor="#fb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,38h1zM58,38h1zM35,43h1zM44,43h1zM34,44h1zM39,44h1zM44,44h1zM39,45h1zM46,45h1zM51,45h1zM50,46h1zM62,46h1zM70,47h1zM64,49h1zM71,49h1zM37,51h1zM52,51h1zM37,52h1zM53,52h1zM37,56h1zM53,56h1zM37,57h1zM71,59h1zM70,61h1zM62,62h1zM39,63h1zM34,64h1zM39,64h1zM54,64h1zM56,64h2zM44,65h1zM67,66h1zM66,67h1zM64,68h1zM63,69h1zM52,70h1z"
android:strokeColor="#fe000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,38h4zM49,39h14zM48,40h16zM46,41h20zM45,42h22zM36,43h2zM45,43h23zM35,44h4zM45,44h24zM34,45h5zM47,45h4zM60,45h10zM34,46h5zM48,46h2zM63,46h7zM34,47h5zM63,47h7zM34,48h5zM64,48h7zM34,49h5zM65,49h6zM34,50h4zM65,50h7zM34,51h3zM49,51h3zM65,51h8zM34,52h3zM49,52h4zM65,52h8zM34,53h3zM48,53h7zM66,53h7zM34,54h3zM48,54h7zM66,54h7zM34,55h3zM48,55h7zM66,55h7zM34,56h3zM49,56h4zM65,56h8zM34,57h3zM49,57h4zM65,57h8zM34,58h4zM50,58h1zM65,58h7zM34,59h5zM65,59h6zM34,60h5zM64,60h7zM34,61h5zM63,61h7zM34,62h5zM48,62h2zM63,62h7zM34,63h5zM47,63h4zM61,63h9zM35,64h4zM45,64h9zM55,64h1zM58,64h11zM35,65h4zM45,65h23zM45,66h22zM46,67h20zM48,68h16zM48,69h15zM53,70h7z"
android:strokeColor="#ff000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,38h1zM47,40h1zM66,41h1zM43,44h1zM39,46h1zM64,50h1zM65,53h1zM60,63h1zM40,64h1z"
android:strokeColor="#fa000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,38h1zM49,59h1zM39,61h1zM59,63h1z"
android:strokeColor="#ec000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,38h1z"
android:strokeColor="#c5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,38h1zM39,59h1zM65,69h1z"
android:strokeColor="#6d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M46,39h1zM39,42h1zM64,70h1z"
android:strokeColor="#2e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,39h1zM42,43h1z"
android:strokeColor="#86000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,39h1zM63,39h1zM45,45h1zM62,61h1zM37,66h1z"
android:strokeColor="#f1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,39h1zM40,43h1zM33,44h1z"
android:strokeColor="#97000000"
android:strokeWidth="1.0" />
<path
android:pathData="M65,39h1zM55,72h1z"
android:strokeColor="#33000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,40h1zM32,45h1zM59,47h1zM39,51h1zM40,60h1zM32,63h1z"
android:strokeColor="#0a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,40h1z"
android:strokeColor="#80000000"
android:strokeWidth="1.0" />
<path
android:pathData="M46,40h1zM50,47h1zM53,51h1z"
android:strokeColor="#dd000000"
android:strokeWidth="1.0" />
<path
android:pathData="M65,40h1z"
android:strokeColor="#e5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M66,40h1z"
android:strokeColor="#82000000"
android:strokeWidth="1.0" />
<path
android:pathData="M67,40h1z"
android:strokeColor="#1a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M35,41h1zM69,42h1zM48,71h1z"
android:strokeColor="#0e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M36,41h1z"
android:strokeColor="#26000000"
android:strokeWidth="1.0" />
<path
android:pathData="M43,41h1zM46,61h1z"
android:strokeColor="#12000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,41h1z"
android:strokeColor="#8b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,41h1zM72,50h1z"
android:strokeColor="#f3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M68,41h1zM53,50h1z"
android:strokeColor="#22000000"
android:strokeWidth="1.0" />
<path
android:pathData="M34,42h1z"
android:strokeColor="#3e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M36,42h1zM39,43h1zM49,70h1zM54,71h1z"
android:strokeColor="#e3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M37,42h1zM44,67h1z"
android:strokeColor="#cc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,42h1zM64,53h1z"
android:strokeColor="#6e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M42,42h1zM56,46h1zM72,62h1z"
android:strokeColor="#0d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,42h1zM65,55h1zM39,62h1zM61,62h1zM70,63h1z"
android:strokeColor="#f7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M67,42h1zM52,45h1zM70,46h1zM49,50h2zM37,53h1zM71,60h1zM46,63h1zM44,64h1zM43,65h1zM68,65h1zM51,70h1z"
android:strokeColor="#fc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M68,42h1zM72,60h1z"
android:strokeColor="#a2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,43h1zM43,63h1z"
android:strokeColor="#44000000"
android:strokeWidth="1.0" />
<path
android:pathData="M34,43h1zM54,45h1zM46,46h1zM49,49h1z"
android:strokeColor="#dc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,43h1zM40,44h1zM62,47h1zM37,54h1zM72,58h1z"
android:strokeColor="#f9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,43h1zM47,51h1z"
android:strokeColor="#2c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M43,43h1zM68,43h1zM71,48h1zM50,62h1zM65,68h1zM61,70h1z"
android:strokeColor="#f8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M69,43h1zM62,48h1z"
android:strokeColor="#92000000"
android:strokeWidth="1.0" />
<path
android:pathData="M70,43h1zM40,66h1z"
android:strokeColor="#11000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,44h1z"
android:strokeColor="#b5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M70,44h1z"
android:strokeColor="#79000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,45h1zM33,52h1zM33,56h1zM58,63h1z"
android:strokeColor="#c9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,45h1zM51,50h1z"
android:strokeColor="#d7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,45h1zM46,47h1zM45,62h1z"
android:strokeColor="#37000000"
android:strokeWidth="1.0" />
<path
android:pathData="M42,45h1z"
android:strokeColor="#16000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,45h1zM47,54h1z"
android:strokeColor="#b6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,45h1zM34,65h1z"
android:strokeColor="#ee000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,45h1zM33,48h1zM33,60h1zM53,63h1z"
android:strokeColor="#cb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,45h1zM33,51h1zM33,57h1z"
android:strokeColor="#c7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,45h1z"
android:strokeColor="#d1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,45h1zM56,71h1z"
android:strokeColor="#eb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M70,45h1zM48,51h1z"
android:strokeColor="#ea000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,45h1zM70,65h1zM56,72h1z"
android:strokeColor="#36000000"
android:strokeWidth="1.0" />
<path
android:pathData="M32,46h1zM32,47h1zM32,48h1zM32,49h1zM32,50h1zM32,51h1zM32,52h1zM32,53h1zM32,54h1zM74,54h1zM32,55h1zM32,56h1zM32,57h1zM32,58h1zM32,59h1zM62,59h1zM32,60h1zM61,60h1zM32,61h1zM32,62h1zM33,66h1z"
android:strokeColor="#0b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,46h1zM33,49h1zM33,54h1zM48,58h1zM33,59h1zM33,62h1z"
android:strokeColor="#c6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,46h1z"
android:strokeColor="#77000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,46h1zM38,55h1z"
android:strokeColor="#6b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,46h1zM61,46h1zM55,54h1zM48,56h1zM49,58h1zM64,59h1zM70,62h1zM51,63h1zM69,64h1zM44,66h1zM47,68h1zM60,70h1z"
android:strokeColor="#fd000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,46h1zM63,60h1z"
android:strokeColor="#e7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,46h1zM64,54h1z"
android:strokeColor="#4e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,46h1z"
android:strokeColor="#2a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,46h1zM53,62h1z"
android:strokeColor="#1b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,46h1zM63,58h1z"
android:strokeColor="#45000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,46h1z"
android:strokeColor="#95000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,46h1z"
android:strokeColor="#e0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,46h1z"
android:strokeColor="#93000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,47h1zM33,61h1z"
android:strokeColor="#ca000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,47h1zM65,54h1zM51,58h1zM46,68h1z"
android:strokeColor="#f2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,47h1zM55,57h1z"
android:strokeColor="#40000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,47h1z"
android:strokeColor="#a8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,47h1zM68,67h1z"
android:strokeColor="#4c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,47h1zM50,48h1z"
android:strokeColor="#48000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,47h1zM64,69h1z"
android:strokeColor="#df000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,47h1zM53,71h1z"
android:strokeColor="#d4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,47h1zM61,48h1zM73,59h1z"
android:strokeColor="#24000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,48h1zM40,65h1z"
android:strokeColor="#c4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,48h1z"
android:strokeColor="#52000000"
android:strokeWidth="1.0" />
<path
android:pathData="M49,48h1zM64,57h1z"
android:strokeColor="#c3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,48h1zM38,50h1zM53,57h1zM49,61h1z"
android:strokeColor="#f5000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,48h1z"
android:strokeColor="#7f000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,49h1zM42,64h1z"
android:strokeColor="#88000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,49h1zM67,68h1z"
android:strokeColor="#43000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,49h1zM42,65h1z"
android:strokeColor="#ac000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,49h1z"
android:strokeColor="#25000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,49h1zM51,61h1zM69,66h1z"
android:strokeColor="#1e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,49h1zM33,50h1zM33,58h1z"
android:strokeColor="#ce000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,49h1z"
android:strokeColor="#17000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,50h1zM48,60h1zM43,67h1z"
android:strokeColor="#3d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,50h1zM48,70h1z"
android:strokeColor="#af000000"
android:strokeWidth="1.0" />
<path
android:pathData="M52,50h1zM73,57h1z"
android:strokeColor="#8d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,50h1zM47,61h1z"
android:strokeColor="#5c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,50h1z"
android:strokeColor="#4d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,51h1z"
android:strokeColor="#b2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,51h1z"
android:strokeColor="#75000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,51h1z"
android:strokeColor="#18000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,51h1z"
android:strokeColor="#13000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,51h1z"
android:strokeColor="#d2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,51h1z"
android:strokeColor="#81000000"
android:strokeWidth="1.0" />
<path
android:pathData="M74,51h1zM57,54h1zM46,56h1zM55,58h1zM40,59h1zM47,59h1zM44,62h1zM35,68h1zM37,68h1zM43,68h1zM60,72h1z"
android:strokeColor="#02000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,52h1z"
android:strokeColor="#94000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,52h1zM46,69h1z"
android:strokeColor="#5b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,52h1zM48,57h1zM47,62h1z"
android:strokeColor="#f0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,52h1z"
android:strokeColor="#7d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,52h1zM74,55h1zM74,56h1zM42,63h1zM34,67h1zM68,68h1z"
android:strokeColor="#06000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,52h1zM61,61h1zM54,63h1z"
android:strokeColor="#a1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,53h1zM33,55h1zM33,63h1zM47,69h1z"
android:strokeColor="#cd000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,53h1z"
android:strokeColor="#78000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,53h1z"
android:strokeColor="#9b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,53h1zM64,58h1zM52,63h1z"
android:strokeColor="#f4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,53h1z"
android:strokeColor="#2d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,53h1z"
android:strokeColor="#bf000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,54h1zM33,65h1zM41,65h1z"
android:strokeColor="#61000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,54h1z"
android:strokeColor="#74000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,54h1zM38,66h1z"
android:strokeColor="#ba000000"
android:strokeWidth="1.0" />
<path
android:pathData="M46,55h1z"
android:strokeColor="#08000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,55h1z"
android:strokeColor="#a6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M56,55h1z"
android:strokeColor="#47000000"
android:strokeWidth="1.0" />
<path
android:pathData="M64,55h1z"
android:strokeColor="#63000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,56h1zM64,56h1zM55,63h2z"
android:strokeColor="#90000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,56h1z"
android:strokeColor="#73000000"
android:strokeWidth="1.0" />
<path
android:pathData="M55,56h1z"
android:strokeColor="#b0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,56h1zM46,62h1z"
android:strokeColor="#a9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,57h1z"
android:strokeColor="#3a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M54,57h1z"
android:strokeColor="#ae000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,57h1zM73,60h1zM45,69h1zM59,72h1z"
android:strokeColor="#0c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M38,58h1zM48,61h1zM67,67h1z"
android:strokeColor="#e4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,58h1z"
android:strokeColor="#49000000"
android:strokeWidth="1.0" />
<path
android:pathData="M73,58h1zM34,66h1z"
android:strokeColor="#65000000"
android:strokeWidth="1.0" />
<path
android:pathData="M48,59h1z"
android:strokeColor="#5d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,59h1z"
android:strokeColor="#db000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,59h1zM40,62h1zM52,62h1z"
android:strokeColor="#62000000"
android:strokeWidth="1.0" />
<path
android:pathData="M63,59h1z"
android:strokeColor="#a0000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,59h1z"
android:strokeColor="#e2000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,60h1zM71,62h1zM70,64h1z"
android:strokeColor="#b4000000"
android:strokeWidth="1.0" />
<path
android:pathData="M49,60h1z"
android:strokeColor="#b7000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,60h1z"
android:strokeColor="#67000000"
android:strokeWidth="1.0" />
<path
android:pathData="M40,61h1z"
android:strokeColor="#34000000"
android:strokeWidth="1.0" />
<path
android:pathData="M50,61h1z"
android:strokeColor="#b3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,61h1z"
android:strokeColor="#e6000000"
android:strokeWidth="1.0" />
<path
android:pathData="M72,61h1z"
android:strokeColor="#3c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,62h1zM40,63h1z"
android:strokeColor="#be000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,62h1z"
android:strokeColor="#14000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,62h1z"
android:strokeColor="#4a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,62h1z"
android:strokeColor="#a3000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,63h1zM44,68h1z"
android:strokeColor="#20000000"
android:strokeWidth="1.0" />
<path
android:pathData="M44,63h1z"
android:strokeColor="#85000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,63h1z"
android:strokeColor="#da000000"
android:strokeWidth="1.0" />
<path
android:pathData="M57,63h1z"
android:strokeColor="#9c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M71,63h1zM50,71h1z"
android:strokeColor="#51000000"
android:strokeWidth="1.0" />
<path
android:pathData="M33,64h1zM52,71h1z"
android:strokeColor="#ad000000"
android:strokeWidth="1.0" />
<path
android:pathData="M41,64h1z"
android:strokeColor="#9d000000"
android:strokeWidth="1.0" />
<path
android:pathData="M69,65h1z"
android:strokeColor="#bc000000"
android:strokeWidth="1.0" />
<path
android:pathData="M35,66h1zM55,71h1zM57,71h1z"
android:strokeColor="#e8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M39,66h1z"
android:strokeColor="#58000000"
android:strokeWidth="1.0" />
<path
android:pathData="M42,66h1zM58,72h1z"
android:strokeColor="#1c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M43,66h1z"
android:strokeColor="#c8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M35,67h1z"
android:strokeColor="#4b000000"
android:strokeWidth="1.0" />
<path
android:pathData="M36,67h1z"
android:strokeColor="#84000000"
android:strokeWidth="1.0" />
<path
android:pathData="M37,67h1z"
android:strokeColor="#5a000000"
android:strokeWidth="1.0" />
<path
android:pathData="M45,68h1z"
android:strokeColor="#aa000000"
android:strokeWidth="1.0" />
<path
android:pathData="M66,68h1z"
android:strokeColor="#b1000000"
android:strokeWidth="1.0" />
<path
android:pathData="M47,70h1z"
android:strokeColor="#28000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,70h1z"
android:strokeColor="#e9000000"
android:strokeWidth="1.0" />
<path
android:pathData="M51,71h1z"
android:strokeColor="#8c000000"
android:strokeWidth="1.0" />
<path
android:pathData="M58,71h1z"
android:strokeColor="#d8000000"
android:strokeWidth="1.0" />
<path
android:pathData="M59,71h1z"
android:strokeColor="#bb000000"
android:strokeWidth="1.0" />
<path
android:pathData="M60,71h1z"
android:strokeColor="#8e000000"
android:strokeWidth="1.0" />
<path
android:pathData="M61,71h1z"
android:strokeColor="#54000000"
android:strokeWidth="1.0" />
<path
android:pathData="M62,71h1z"
android:strokeColor="#38000000"
android:strokeWidth="1.0" />
<path
android:pathData="M53,72h1z"
android:strokeColor="#19000000"
android:strokeWidth="1.0" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Some files were not shown because too many files have changed in this diff Show More