Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gracefully ignore non-vector images #613

Merged
merged 1 commit into from
May 28, 2024
Merged
Show file tree
Hide file tree
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 @@ -64,7 +64,7 @@ abstract class EasyLauncherTask @Inject constructor(private val objects: ObjectF

is IconFile.Adaptive -> iconFile.processAdaptiveIcon()

is IconFile.XmlDrawableResource -> iconFile.processDrawable()
is IconFile.XmlDrawable -> iconFile.processDrawable()
}
}
}
Expand All @@ -86,7 +86,7 @@ abstract class EasyLauncherTask @Inject constructor(private val objects: ObjectF
iconNames.flatMap { (iconName, iconType) ->
objects.getIconFiles(parent = resDir, iconName = iconName)
.map { iconFile ->
iconFile.tryParseXmlFile() ?: when (iconType) {
iconFile.tryParseXmlIcon() ?: when (iconType) {
IconType.Default -> IconFile.Raster(iconFile)
IconType.Round -> IconFile.RasterRound(iconFile)
}
Expand All @@ -104,7 +104,10 @@ abstract class EasyLauncherTask @Inject constructor(private val objects: ObjectF
iconFiles.forEach { iconFile ->
val outputFile = iconFile.getOutputFile()
if (iconFile.extension == "xml") {
iconFile.transformXml(outputFile, minSdkVersion.get(), filters.get())
when (val drawable = iconFile.tryParseXmlDrawable()) {
is IconFile.XmlDrawable.Vector -> drawable.transform(outputFile, minSdkVersion.get(), filters.get())
null -> log.info { "Skipped $iconFile due to unrecognised file format" }
}
} else {
iconFile.transformImage(
outputFile = outputFile,
Expand All @@ -116,9 +119,10 @@ abstract class EasyLauncherTask @Inject constructor(private val objects: ObjectF
}
}

private fun IconFile.XmlDrawableResource.processDrawable() {
val outputFile = file.getOutputFile()
file.transformXml(outputFile, minSdkVersion.get(), filters.get())
private fun IconFile.XmlDrawable.processDrawable() {
when (this) {
is IconFile.XmlDrawable.Vector -> transform(file.getOutputFile(), minSdkVersion.get(), filters.get())
}
}

private fun File.getOutputFile(): File = File(outputDir.asFile.get(), "${parentFile.name}/$name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package com.project.starter.easylauncher.plugin

import com.project.starter.easylauncher.filter.Canvas
import com.project.starter.easylauncher.filter.EasyLauncherFilter
import com.project.starter.easylauncher.plugin.models.toSize
import groovy.xml.XmlSlurper
import com.project.starter.easylauncher.plugin.models.IconFile
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
Expand All @@ -19,11 +18,7 @@ internal fun File.transformImage(outputFile: File, filters: List<EasyLauncherFil
ImageIO.write(image, extension, outputFile)
}

internal fun File.transformXml(outputFile: File, minSdkVersion: Int, filters: List<EasyLauncherFilter>) {
val iconXml = XmlSlurper().parse(this)
val width = iconXml.property("@android:width")?.toSize().let(::requireNotNull)
val height = iconXml.property("@android:height")?.toSize().let(::requireNotNull)

internal fun IconFile.XmlDrawable.Vector.transform(outputFile: File, minSdkVersion: Int, filters: List<EasyLauncherFilter>) {
val drawableRoot = outputFile.parentFile // eg. debug/drawable/

val layers = filters.mapIndexed { index, filter ->
Expand All @@ -32,8 +27,8 @@ internal fun File.transformXml(outputFile: File, minSdkVersion: Int, filters: Li

densities.forEach { (qualifier, multiplier) ->
val overlay = BufferedImage(
(width.value * multiplier).roundToInt(),
(height.value * multiplier).roundToInt(),
(width * multiplier).roundToInt(),
(height * multiplier).roundToInt(),
BufferedImage.TYPE_INT_ARGB,
)
val canvas = Canvas(overlay, adaptive = true)
Expand All @@ -57,13 +52,13 @@ internal fun File.transformXml(outputFile: File, minSdkVersion: Int, filters: Li
val versionSuffix = if (minSdkVersion >= ANDROID_OREO) "" else "-v26"
val v26DrawableRoot = drawableRoot.parentFile.resolve("${drawableRoot.normalizedName}-anydpi$versionSuffix")

copyTo(v26DrawableRoot.resolve("easy_$name"), overwrite = true)
file.copyTo(v26DrawableRoot.resolve("easy_${file.name}"), overwrite = true)
v26DrawableRoot.resolve(outputFile.name).writeText(
"""
|<?xml version="1.0" encoding="utf-8"?>
|<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
| <item android:drawable="@${drawableRoot.normalizedName}/easy_$nameWithoutExtension" />
| <item android:drawable="@${drawableRoot.normalizedName}/easy_${file.nameWithoutExtension}" />
|
|$layers
|</layer-list>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.project.starter.easylauncher.plugin

import com.project.starter.easylauncher.plugin.models.IconFile
import com.project.starter.easylauncher.plugin.models.IconType
import com.project.starter.easylauncher.plugin.models.toSize
import groovy.xml.XmlSlurper
import groovy.xml.slurpersupport.GPathResult
import java.io.File
Expand All @@ -23,7 +24,7 @@ private val regex by lazy { "\\\$\\{([^{}]*)}".toRegex() }
private fun String.applyPlaceholders(manifestPlaceholders: Map<String, Any>): String =
replace(regex) { manifestPlaceholders[it.groups[1]?.value]?.toString() ?: it.value }

internal fun File.tryParseXmlFile(): IconFile? {
internal fun File.tryParseXmlIcon(): IconFile? {
if (extension != "xml") {
return null
}
Expand All @@ -44,7 +45,23 @@ internal fun File.tryParseXmlFile(): IconFile? {
monochrome = monochromeDrawable,
)
} else {
IconFile.XmlDrawableResource(file = this)
tryParseXmlDrawable()
}
}

internal fun File.tryParseXmlDrawable(): IconFile.XmlDrawable? {
val iconXml = XmlSlurper().parse(this)
val width = iconXml.property("@android:width")?.toSize()?.value
val height = iconXml.property("@android:height")?.toSize()?.value

return when {
width != null && height != null -> IconFile.XmlDrawable.Vector(
file = this,
width = width,
height = height,
)

else -> null
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,12 @@ internal sealed class IconFile {
val monochrome: String?,
) : IconFile()

data class XmlDrawableResource(val file: File) : IconFile()
sealed class XmlDrawable : IconFile() {

data class Vector(
val file: File,
val width: Int,
val height: Int,
) : XmlDrawable()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.project.starter.easylauncher.plugin
import com.project.starter.easylauncher.filter.ChromeLikeFilter
import com.project.starter.easylauncher.filter.ColorRibbonFilter
import com.project.starter.easylauncher.filter.OverlayFilter
import com.project.starter.easylauncher.plugin.models.IconFile
import com.project.starter.easylauncher.plugin.utils.vectorFile
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
Expand All @@ -14,24 +15,24 @@ internal class IconTransformerTest {

@TempDir
lateinit var tempDir: File
lateinit var sourceIcon: File
lateinit var sourceIcon: IconFile.XmlDrawable.Vector
lateinit var output: File

@BeforeEach
internal fun setUp() {
val drawable = tempDir.resolve("drawable").apply {
mkdir()
}
sourceIcon = drawable.resolve("icon_resource.xml")
sourceIcon.writeText(vectorFile())
val sourceIconFile = drawable.resolve("icon_resource.xml").apply { writeText(vectorFile()) }
sourceIcon = sourceIconFile.tryParseXmlDrawable() as IconFile.XmlDrawable.Vector

output = drawable.resolve("output.xml")
}

@Test
fun `transforms vector icon pre api 26`() {
val expected = tempDir.resolve("drawable-anydpi-v26/output.xml")
sourceIcon.transformXml(
sourceIcon.transform(
outputFile = output,
minSdkVersion = 21,
filters = listOf(
Expand Down Expand Up @@ -65,7 +66,7 @@ internal class IconTransformerTest {
@Test
fun `transforms vector icon since api 26`() {
val expected = tempDir.resolve("drawable-anydpi/output.xml")
sourceIcon.transformXml(
sourceIcon.transform(
outputFile = output,
minSdkVersion = 26,
filters = listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ internal class XmlReaderTest {
""".trimIndent(),
)

val icon = adaptiveIcon.tryParseXmlFile() as IconFile.Adaptive
val icon = adaptiveIcon.tryParseXmlIcon() as IconFile.Adaptive

assertThat(icon.background).isEqualTo("@drawable/ic_launcher_background")
assertThat(icon.foreground).isEqualTo("@mipmap/ic_launcher_foreground")
Expand All @@ -234,7 +234,7 @@ internal class XmlReaderTest {
""".trimIndent(),
)

val icon = adaptiveIcon.tryParseXmlFile() as IconFile.Adaptive
val icon = adaptiveIcon.tryParseXmlIcon() as IconFile.Adaptive

assertThat(icon.background).isEqualTo("@drawable/ic_launcher_background")
assertThat(icon.foreground).isEqualTo("@mipmap/ic_launcher_foreground")
Expand All @@ -247,9 +247,15 @@ internal class XmlReaderTest {
val drawableResource = tempDir.resolve("ic_launcher.xml")
drawableResource.writeText(vectorFile())

val icon = drawableResource.tryParseXmlFile()
val icon = drawableResource.tryParseXmlIcon()

assertThat(icon).isEqualTo(IconFile.XmlDrawableResource(file = drawableResource))
assertThat(icon).isEqualTo(
IconFile.XmlDrawable.Vector(
file = drawableResource,
width = 24,
height = 24,
),
)
}

@Test
Expand All @@ -266,7 +272,7 @@ internal class XmlReaderTest {
""".trimIndent(),
)

val icon = adaptiveIcon.tryParseXmlFile()
val icon = adaptiveIcon.tryParseXmlIcon()

assertThat(icon).isNull()
}
Expand Down
20 changes: 20 additions & 0 deletions sample/example-drawables/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apply plugin: 'com.starter.application.android'
apply plugin: 'com.starter.easylauncher'

android {
namespace "com.example.vector"
defaultConfig {
minSdkVersion 28
}
buildTypes {
named("release") {
debuggable false
signingConfig signingConfigs.debug
}
}
flavorDimensions += "reportedBugs"
}

dependencies {
implementation project(":adaptive-support")
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.starter.easylauncher.screenshot

import com.example.custom.adaptive.MainActivity
import com.starter.easylauncher.recordScreenshot
import org.junit.Test

internal class IconsTest {

@Test
fun doScreenshot() {
recordScreenshot<MainActivity>(flavor = "insets")
}
}
9 changes: 9 additions & 0 deletions sample/example-drawables/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:icon="@mipmap/ic_launcher"
android:label="${appName}"
/>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24"
>

<path
android:fillColor="@android:color/white"
android:pathData="M17,5L3,5c-1.1,0 -2,0.89 -2,2v9h2c0,1.65 1.34,3 3,3s3,-1.35 3,-3h5.5c0,1.65 1.34,3 3,3s3,-1.35 3,-3L23,16v-5l-6,-6zM3,11L3,7h4v4L3,11zM6,17.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM13,11L9,11L9,7h4v4zM17.5,17.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM15,11L15,7h1l4,4h-5z"
/>

</vector>
Loading