Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
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",
Expand All @@ -14,14 +15,43 @@ 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"

private val RGB = Regex("#[0-9A-Fa-f]{6}")

val valencedIcon = patch("Valenced icon") {
description("Puts Discord's launcher icon on Valenced's cyan.")
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(
"icon",
title = "Custom 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 {
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, opaque(options[backgroundOption]))
resources.addColor(FOREGROUND, opaque(options[foregroundOption]))
}
for (icon in LAUNCHER_ICONS) {
// Some icons may not exist due to resource shrinking
if (!resources.exists("mipmap", icon)) continue
Expand All @@ -34,17 +64,26 @@ 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"
})
}
}
}
}
}
}

private fun opaque(rgb: String): String {
require(RGB.matches(rgb)) { "$rgb isn't a color like #37EBFF" }
return "#FF" + rgb.substring(1)
}