From 9152baf0b7e0dd9461a25cfcd0e84d36733da0bc Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Fri, 30 Oct 2026 11:25:15 -0400 Subject: [PATCH 1/2] custom app icon --- .../valenced/patches/discord/ValencedIcon.kt | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt b/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt index af91196b..67481b58 100644 --- a/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt +++ b/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt @@ -4,6 +4,7 @@ package app.valenced.patches.discord import app.reseam.patch.patch +import java.io.File /** Discord's launcher icons, both adaptive icons over a channel colour. */ private val LAUNCHER_ICONS = listOf( @@ -14,14 +15,27 @@ private val LAUNCHER_ICONS = listOf( private const val BACKGROUND = "valenced_icon_background" private const val FOREGROUND = "valenced_icon_foreground" +private const val CUSTOM = "valenced_icon_custom" val valencedIcon = patch("Valenced icon") { - description("Puts Discord's launcher icon on Valenced's cyan.") + description("Puts Discord's launcher icon on Valenced's cyan, or replaces it with an image.") compatibleWith(DISCORD) + val iconOption = pathOption( + "icon", + title = "Custom icon", + description = "The image to use as the launcher icon.", + ) + execute { - resources.addColor(BACKGROUND, "#FF37EBFF") - resources.addColor(FOREGROUND, "#FF000000") + val custom = options.getOrNull(iconOption)?.let { File(it.path).readBytes() } + if (custom != null) { + resources.addColor(BACKGROUND, "#FF000000") + resources.addFile("drawable", CUSTOM, "res/$CUSTOM.png", custom) + } else { + resources.addColor(BACKGROUND, "#FF37EBFF") + resources.addColor(FOREGROUND, "#FF000000") + } for (icon in LAUNCHER_ICONS) { // Some icons may not exist due to resource shrinking if (!resources.exists("mipmap", icon)) continue @@ -34,15 +48,19 @@ val valencedIcon = patch("Valenced icon") { val background = findByTag("background").singleOrNull() ?: error("$path has no background layer") background["android:drawable"] = "@color/$BACKGROUND" - // The foreground is a PNG mipmap shared with the rest of the app, so tint an inline - // copy rather than the mipmap itself. A layer without android:drawable inflates its child. val foreground = findByTag("foreground").singleOrNull() ?: error("$path has no foreground layer") val drawable = foreground["android:drawable"] ?: error("$path has no foreground drawable") - foreground.removeAttribute("android:drawable") - foreground.appendChild(createElement("bitmap").apply { - this["android:src"] = drawable - this["android:tint"] = "@color/$FOREGROUND" - }) + if (custom != null) { + foreground["android:drawable"] = "@drawable/$CUSTOM" + } else { + // The foreground is a PNG mipmap shared with the rest of the app, so tint an inline + // copy rather than the mipmap itself. A layer without android:drawable inflates its child. + foreground.removeAttribute("android:drawable") + foreground.appendChild(createElement("bitmap").apply { + this["android:src"] = drawable + this["android:tint"] = "@color/$FOREGROUND" + }) + } } } } From 574d5ce34c4f448c0a99c514c2a3f1324971863e Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Sat, 31 Oct 2026 12:01:44 -0400 Subject: [PATCH 2/2] colors --- .../valenced/patches/discord/ValencedIcon.kt | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt b/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt index 67481b58..ab760b6f 100644 --- a/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt +++ b/android/patches/apps/discord/patch/src/main/kotlin/app/valenced/patches/discord/ValencedIcon.kt @@ -6,7 +6,7 @@ package app.valenced.patches.discord import app.reseam.patch.patch import java.io.File -/** Discord's launcher icons, both adaptive icons over a channel colour. */ +/** Discord's launcher icons, both adaptive icons over a channel color. */ private val LAUNCHER_ICONS = listOf( "ic_logo_square", "ic_logo_round", "ic_logo_square_beta", "ic_logo_round_beta", @@ -17,8 +17,10 @@ private const val BACKGROUND = "valenced_icon_background" private const val FOREGROUND = "valenced_icon_foreground" private const val CUSTOM = "valenced_icon_custom" +private val RGB = Regex("#[0-9A-Fa-f]{6}") + val valencedIcon = patch("Valenced icon") { - description("Puts Discord's launcher icon on Valenced's cyan, or replaces it with an image.") + description("Puts Discord's launcher icon on a color, Valenced's cyan by default, or replaces it with an image.") compatibleWith(DISCORD) val iconOption = pathOption( @@ -27,14 +29,28 @@ val valencedIcon = patch("Valenced icon") { description = "The image to use as the launcher icon.", ) + val backgroundOption = stringOption( + "background", + title = "Background color", + description = "The color behind Discord's logo, such as #37EBFF.", + default = "#37EBFF", + ) + + val foregroundOption = stringOption( + "foreground", + title = "Logo color", + description = "The color of Discord's logo, such as #000000.", + default = "#000000", + ) + execute { val custom = options.getOrNull(iconOption)?.let { File(it.path).readBytes() } if (custom != null) { resources.addColor(BACKGROUND, "#FF000000") resources.addFile("drawable", CUSTOM, "res/$CUSTOM.png", custom) } else { - resources.addColor(BACKGROUND, "#FF37EBFF") - resources.addColor(FOREGROUND, "#FF000000") + resources.addColor(BACKGROUND, opaque(options[backgroundOption])) + resources.addColor(FOREGROUND, opaque(options[foregroundOption])) } for (icon in LAUNCHER_ICONS) { // Some icons may not exist due to resource shrinking @@ -66,3 +82,8 @@ val valencedIcon = patch("Valenced icon") { } } } + +private fun opaque(rgb: String): String { + require(RGB.matches(rgb)) { "$rgb isn't a color like #37EBFF" } + return "#FF" + rgb.substring(1) +}