From 82de31643c68edeea308416a5e0eaa6abb4132f3 Mon Sep 17 00:00:00 2001 From: Sergio Belda Galbis Date: Sun, 4 Feb 2024 01:06:05 +0100 Subject: [PATCH] Add stroke properties to generated Path (#14) Also, refactor ImageVectorGenerator code and add default values for Vector and VectorNode.Path classes. --- .../vectorize/generator/ImageParser.kt | 76 ++++++++--- .../generator/ImageVectorGenerator.kt | 125 ++++++++++++------ .../compose/vectorize/generator/Names.kt | 27 +++- .../vectorize/generator/vector/StrokeCap.kt | 29 ++++ .../vectorize/generator/vector/StrokeJoin.kt | 29 ++++ .../vectorize/generator/vector/Vector.kt | 31 ++++- .../compose/vectorize/sample/MainScreen.kt | 54 +++++++- .../illustrations/compose-multiplatform.xml | 19 +++ 8 files changed, 320 insertions(+), 70 deletions(-) create mode 100644 compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeCap.kt create mode 100644 compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeJoin.kt create mode 100644 sample-mpp/common/xml-images/illustrations/compose-multiplatform.xml diff --git a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageParser.kt b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageParser.kt index 4a30f3d..6f839aa 100644 --- a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageParser.kt +++ b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageParser.kt @@ -18,8 +18,21 @@ package dev.sergiobelda.compose.vectorize.generator import dev.sergiobelda.compose.vectorize.generator.vector.FillType import dev.sergiobelda.compose.vectorize.generator.vector.PathParser +import dev.sergiobelda.compose.vectorize.generator.vector.StrokeCap +import dev.sergiobelda.compose.vectorize.generator.vector.StrokeJoin import dev.sergiobelda.compose.vectorize.generator.vector.Vector +import dev.sergiobelda.compose.vectorize.generator.vector.Vector.Companion.DefaultHeight +import dev.sergiobelda.compose.vectorize.generator.vector.Vector.Companion.DefaultViewportHeight +import dev.sergiobelda.compose.vectorize.generator.vector.Vector.Companion.DefaultViewportWidth +import dev.sergiobelda.compose.vectorize.generator.vector.Vector.Companion.DefaultWidth import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultFillAlpha +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultFillType +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeAlpha +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeCap +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeLineJoin +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeLineMiter +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeWidth import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser.END_DOCUMENT import org.xmlpull.v1.XmlPullParser.END_TAG @@ -43,10 +56,10 @@ class ImageParser(private val image: Image) { check(parser.name == VECTOR) { "The start tag must be !" } - var width = "" - var height = "" - var viewportWidth = 0f - var viewportHeight = 0f + var width = DefaultWidth + var height = DefaultHeight + var viewportWidth = DefaultViewportWidth + var viewportHeight = DefaultViewportHeight val nodes = mutableListOf() var currentGroup: VectorNode.Group? = null @@ -56,10 +69,10 @@ class ImageParser(private val image: Image) { START_TAG -> { when (parser.name) { VECTOR -> { - width = parser.getValueAsString(WIDTH).processDpDimension() - height = parser.getValueAsString(HEIGHT).processDpDimension() - viewportWidth = parser.getValueAsFloat(VIEWPORT_WIDTH) ?: 0f - viewportHeight = parser.getValueAsFloat(VIEWPORT_HEIGHT) ?: 0f + width = parser.getValueAsString(WIDTH)?.processDpDimension() ?: DefaultWidth + height = parser.getValueAsString(HEIGHT)?.processDpDimension() ?: DefaultHeight + viewportWidth = parser.getValueAsFloat(VIEWPORT_WIDTH) ?: DefaultViewportWidth + viewportHeight = parser.getValueAsFloat(VIEWPORT_HEIGHT) ?: DefaultViewportHeight } PATH -> { @@ -68,21 +81,40 @@ class ImageParser(private val image: Image) { PATH_DATA, ) val fillAlpha = parser.getValueAsFloat(FILL_ALPHA) - val strokeAlpha = parser.getValueAsFloat(STROKE_ALPHA) - val fillColor = parser.getValueAsString(FILL_COLOR).processFillColor() - + val fillColor = parser.getValueAsString(FILL_COLOR)?.processColor() val fillType = when (parser.getAttributeValue(null, FILL_TYPE)) { // evenOdd and nonZero are the only supported values here, where // nonZero is the default if no values are defined. EVEN_ODD -> FillType.EvenOdd - else -> FillType.NonZero + else -> DefaultFillType } + val strokeAlpha = parser.getValueAsFloat(STROKE_ALPHA) + val strokeCap = when (parser.getAttributeValue(null, STROKE_LINE_CAP)) { + ROUND -> StrokeCap.Round + SQUARE -> StrokeCap.Square + else -> DefaultStrokeCap + } + val strokeColor = parser.getValueAsString(STROKE_COLOR)?.processColor() + val strokeLineJoin = + when (parser.getAttributeValue(null, STROKE_LINE_JOIN)) { + BEVEL -> StrokeJoin.Bevel + ROUND -> StrokeJoin.Round + else -> DefaultStrokeLineJoin + } + val strokeMiterLimit = parser.getValueAsFloat(STROKE_MITER_LIMIT) + val strokeWidth = parser.getValueAsFloat(STROKE_WIDTH) + val path = VectorNode.Path( - strokeAlpha = strokeAlpha ?: 1f, - fillAlpha = fillAlpha ?: 1f, - fillColor = fillColor.uppercase(), + fillAlpha = fillAlpha ?: DefaultFillAlpha, + fillColor = fillColor?.uppercase(), fillType = fillType, nodes = PathParser.parsePathString(pathData), + strokeAlpha = strokeAlpha ?: DefaultStrokeAlpha, + strokeCap = strokeCap, + strokeColor = strokeColor, + strokeLineMiter = strokeMiterLimit ?: DefaultStrokeLineMiter, + strokeLineJoin = strokeLineJoin, + strokeWidth = strokeWidth ?: DefaultStrokeWidth, ) if (currentGroup != null) { currentGroup.paths.add(path) @@ -124,8 +156,8 @@ private fun XmlPullParser.getValueAsFloat(name: String): Float? = /** * @return the string value for the attribute [name], or null if it couldn't be found */ -private fun XmlPullParser.getValueAsString(name: String): String = - getAttributeValue(null, name) +private fun XmlPullParser.getValueAsString(name: String): String? = + getAttributeValue(null, name)?.toString() private fun XmlPullParser.seekToStartTag(): XmlPullParser { var type = next() @@ -145,7 +177,7 @@ private fun XmlPullParser.isAtEnd() = private fun String.processDpDimension(): String = this.replace("dp", "") -private fun String.processFillColor(): String { +private fun String.processColor(): String { val diff = ARGB_HEXADECIMAL_COLOR_LENGTH - this.length return if (diff > 0) { this.replace("#", "#${"F".repeat(diff)}") @@ -169,9 +201,17 @@ private const val FILL_TYPE = "android:fillType" private const val HEIGHT = "android:height" private const val PATH_DATA = "android:pathData" private const val STROKE_ALPHA = "android:strokeAlpha" +private const val STROKE_COLOR = "android:strokeColor" +private const val STROKE_LINE_CAP = "android:strokeLineCap" +private const val STROKE_LINE_JOIN = "android:strokeLineJoin" +private const val STROKE_MITER_LIMIT = "android:strokeMiterLimit" +private const val STROKE_WIDTH = "android:strokeWidth" private const val VIEWPORT_HEIGHT = "android:viewportHeight" private const val VIEWPORT_WIDTH = "android:viewportWidth" private const val WIDTH = "android:width" // XML attribute values +private const val BEVEL = "bevel" private const val EVEN_ODD = "evenOdd" +private const val ROUND = "round" +private const val SQUARE = "square" diff --git a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageVectorGenerator.kt b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageVectorGenerator.kt index 88b77d5..58ce962 100644 --- a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageVectorGenerator.kt +++ b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/ImageVectorGenerator.kt @@ -21,12 +21,21 @@ import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.buildCodeBlock import dev.sergiobelda.compose.vectorize.generator.utils.setIndent -import dev.sergiobelda.compose.vectorize.generator.vector.FillType +import dev.sergiobelda.compose.vectorize.generator.vector.StrokeCap +import dev.sergiobelda.compose.vectorize.generator.vector.StrokeJoin import dev.sergiobelda.compose.vectorize.generator.vector.Vector import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultFillAlpha +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultFillType +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeAlpha +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeCap +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeLineJoin +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeLineMiter +import dev.sergiobelda.compose.vectorize.generator.vector.VectorNode.Path.Companion.DefaultStrokeWidth import java.util.Locale /** @@ -103,17 +112,24 @@ class ImageVectorGenerator( ) .addCode( buildCodeBlock { - val controlFlow = buildString { - append("%N = %M(\n") - append(" name = \"%N\",\n") - append(" width = ${vector.width}f,\n") - append(" height = ${vector.height}f,\n") - append(" viewportWidth = ${vector.viewportWidth}f,\n") - append(" viewportHeight = ${vector.viewportHeight}f\n") - append(")") + val parameterList = listOfNotNull( + "name = \"%N\"", + "width = ${vector.width}f", + "height = ${vector.height}f", + "viewportWidth = ${vector.viewportWidth}f", + "viewportHeight = ${vector.viewportHeight}f", + ) + val parameters = if (parameterList.isNotEmpty()) { + parameterList.joinToString( + prefix = "%N = %M(\n\t", + postfix = "\n)", + separator = ",\n\t", + ) + } else { + "" } beginControlFlow( - controlFlow, + parameters, backingProperty, MemberNames.ImageVector, imageName, @@ -167,40 +183,73 @@ private fun CodeBlock.Builder.addPath( path: VectorNode.Path, pathBody: CodeBlock.Builder.() -> Unit, ) { - // Only set the fill type if it is EvenOdd - otherwise it will just be the default. - val setFillType = path.fillType == FillType.EvenOdd + val parameterList = mutableListOf() + val memberList = mutableListOf() - val parameterList = with(path) { - listOfNotNull( - "fill = %M(%M(${fillColor.replace("#", "0x")}))", - "fillAlpha = ${fillAlpha}f".takeIf { fillAlpha != 1f }, - "strokeAlpha = ${strokeAlpha}f".takeIf { strokeAlpha != 1f }, - "pathFillType = %M".takeIf { setFillType }, - ) + with(path) { + memberList.add(MemberNames.Path) + + fillAlpha.takeIf { it != DefaultFillAlpha }?.let { + parameterList.add("fillAlpha = ${it}f") + } + fillColor?.let { + parameterList.add("fill = %M(%M(${it.replace("#", "0x")}))") + memberList.add(MemberNames.SolidColor) + memberList.add(MemberNames.Color) + } + fillType.takeIf { it != DefaultFillType }?.let { + parameterList.add("pathFillType = %M") + memberList.add(MemberNames.PathFillType.EvenOdd) + } + strokeAlpha.takeIf { it != DefaultStrokeAlpha }?.let { + parameterList.add("strokeAlpha = ${it}f") + } + strokeColor?.let { + parameterList.add("stroke = %M(%M(${it.replace("#", "0x")}))") + memberList.add(MemberNames.SolidColor) + memberList.add(MemberNames.Color) + } + strokeCap.takeIf { it != DefaultStrokeCap }?.let { + parameterList.add("strokeLineCap = %M") + when (strokeCap) { + StrokeCap.Round -> memberList.add(MemberNames.StrokeCapType.Round) + StrokeCap.Square -> memberList.add(MemberNames.StrokeCapType.Square) + else -> memberList.add(MemberNames.StrokeCapType.Butt) + } + } + strokeLineMiter.takeIf { it != DefaultStrokeLineMiter }?.let { + parameterList.add("strokeLineMiter = ${strokeLineMiter}f") + } + strokeLineJoin.takeIf { it != DefaultStrokeLineJoin }?.let { + parameterList.add("strokeLineJoin = %M") + when (strokeLineJoin) { + StrokeJoin.Bevel -> memberList.add(MemberNames.StrokeJoinType.Bevel) + StrokeJoin.Round -> memberList.add(MemberNames.StrokeJoinType.Round) + else -> memberList.add(MemberNames.StrokeJoinType.Miter) + } + } + strokeWidth.takeIf { it != DefaultStrokeWidth }?.let { + parameterList.add("strokeLineWidth = ${strokeWidth}f") + } } + addPathParameters(parameterList, memberList) + pathBody() + endControlFlow() +} +private fun CodeBlock.Builder.addPathParameters( + parameterList: List, + memberList: List, +) { val parameters = if (parameterList.isNotEmpty()) { - parameterList.joinToString(prefix = "(", postfix = ")") + parameterList.joinToString( + prefix = "(\n\t", + postfix = "\n)", + separator = ",\n\t", + ) } else { "" } - if (setFillType) { - beginControlFlow( - "%M$parameters", - MemberNames.Path, - MemberNames.SolidColor, - MemberNames.Color, - MemberNames.EvenOdd, - ) - } else { - beginControlFlow( - "%M$parameters", - MemberNames.Path, - MemberNames.SolidColor, - MemberNames.Color, - ) - } - pathBody() - endControlFlow() + beginControlFlow("%M$parameters", *memberList.toTypedArray()) } diff --git a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/Names.kt b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/Names.kt index 12812b6..ad091b2 100644 --- a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/Names.kt +++ b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/Names.kt @@ -34,21 +34,40 @@ enum class PackageNames(val packageName: String) { object ClassNames { val ImageVector = PackageNames.VectorPackage.className("ImageVector") val PathFillType = PackageNames.GraphicsPackage.className("PathFillType", "Companion") + val StrokeCapType = PackageNames.GraphicsPackage.className("StrokeCap", "Companion") + val StrokeJoinType = PackageNames.GraphicsPackage.className("StrokeJoin", "Companion") } /** * [MemberName]s used for image generation. */ object MemberNames { - val Color = MemberName(PackageNames.GraphicsPackage.packageName, "Color") - val EvenOdd = MemberName(ClassNames.PathFillType, "EvenOdd") - val Group = MemberName(PackageNames.VectorPackage.packageName, "group") val ImageVector = MemberName( PackageNames.ComposeVectorizeCore.packageName, "imageVector", ) - val Path = MemberName(PackageNames.VectorPackage.packageName, "path") + + val Color = MemberName(PackageNames.GraphicsPackage.packageName, "Color") val SolidColor = MemberName(PackageNames.GraphicsPackage.packageName, "SolidColor") + + val Group = MemberName(PackageNames.VectorPackage.packageName, "group") + val Path = MemberName(PackageNames.VectorPackage.packageName, "path") + + object PathFillType { + val EvenOdd = MemberName(ClassNames.PathFillType, "EvenOdd") + } + + object StrokeCapType { + val Butt = MemberName(ClassNames.StrokeCapType, "Butt") + val Round = MemberName(ClassNames.StrokeCapType, "Round") + val Square = MemberName(ClassNames.StrokeCapType, "Square") + } + + object StrokeJoinType { + val Bevel = MemberName(ClassNames.StrokeJoinType, "Bevel") + val Miter = MemberName(ClassNames.StrokeJoinType, "Miter") + val Round = MemberName(ClassNames.StrokeJoinType, "Round") + } } /** diff --git a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeCap.kt b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeCap.kt new file mode 100644 index 0000000..0f772da --- /dev/null +++ b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeCap.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Sergio Belda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.sergiobelda.compose.vectorize.generator.vector + +/** + * Styles to use for line endings. + * + * This maps to [androidx.compose.ui.graphics.StrokeCap] used in the framework, and can be defined in XML + * via `android:strokeLineCap`. + */ +enum class StrokeCap { + Butt, + Round, + Square, +} diff --git a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeJoin.kt b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeJoin.kt new file mode 100644 index 0000000..39c4511 --- /dev/null +++ b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/StrokeJoin.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Sergio Belda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.sergiobelda.compose.vectorize.generator.vector + +/** + * Styles to use for line joins. + * + * This maps to [androidx.compose.ui.graphics.StrokeJoin] used in the framework, and can be defined in XML + * via `android:strokeLineJoin`. + */ +enum class StrokeJoin { + Bevel, + Miter, + Round, +} diff --git a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/Vector.kt b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/Vector.kt index 1a2aaa5..fc8265e 100644 --- a/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/Vector.kt +++ b/compose-vectorize-gradle-plugin/src/main/kotlin/dev/sergiobelda/compose/vectorize/generator/vector/Vector.kt @@ -28,15 +28,38 @@ class Vector( val viewportWidth: Float, val viewportHeight: Float, val nodes: List, -) +) { + companion object { + const val DefaultWidth = "24.0" + const val DefaultHeight = "24.0" + const val DefaultViewportWidth = 24f + const val DefaultViewportHeight = 24f + } +} sealed class VectorNode { class Group(val paths: MutableList = mutableListOf()) : VectorNode() class Path( - val strokeAlpha: Float, val fillAlpha: Float, - val fillColor: String, + val fillColor: String?, val fillType: FillType, val nodes: List, - ) : VectorNode() + val strokeAlpha: Float, + val strokeCap: StrokeCap, + val strokeColor: String?, + val strokeLineJoin: StrokeJoin, + val strokeLineMiter: Float, + val strokeWidth: Float, + ) : VectorNode() { + + companion object { + const val DefaultFillAlpha = 1.0f + val DefaultFillType = FillType.NonZero + const val DefaultStrokeAlpha = 1.0f + val DefaultStrokeCap = StrokeCap.Butt + val DefaultStrokeLineJoin = StrokeJoin.Miter + const val DefaultStrokeLineMiter = 4.0f + const val DefaultStrokeWidth = 0.0f + } + } } diff --git a/sample-mpp/common/src/commonMain/kotlin/dev/sergiobelda/compose/vectorize/sample/MainScreen.kt b/sample-mpp/common/src/commonMain/kotlin/dev/sergiobelda/compose/vectorize/sample/MainScreen.kt index dd4a8bc..d0f7937 100644 --- a/sample-mpp/common/src/commonMain/kotlin/dev/sergiobelda/compose/vectorize/sample/MainScreen.kt +++ b/sample-mpp/common/src/commonMain/kotlin/dev/sergiobelda/compose/vectorize/sample/MainScreen.kt @@ -16,24 +16,66 @@ package dev.sergiobelda.compose.vectorize.sample +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Card import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import dev.sergiobelda.compose.vectorize.sample.common.images.Images import dev.sergiobelda.compose.vectorize.sample.common.images.icons.Add +import dev.sergiobelda.compose.vectorize.sample.common.images.illustrations.ComposeMultiplatform @Composable fun MainScreen() { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center + Column( + modifier = Modifier.fillMaxSize().padding(top = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) ) { - IconButton(onClick = {}) { - Icon(Images.Icons.Add, contentDescription = null) + SampleCard( + title = "Images.Icons.Add" + ) { + Icon( + imageVector = Images.Icons.Add, + contentDescription = null + ) + } + SampleCard( + title = "Images.Illustrations.ComposeMultiplatform" + ) { + Image( + imageVector = Images.Illustrations.ComposeMultiplatform, + contentDescription = null, + modifier = Modifier.size(120.dp) + ) + } + } +} + +@Composable +fun SampleCard( + title: String, + content: @Composable () -> Unit +) { + Card(modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp)) { + Column(modifier = Modifier.padding(12.dp)) { + Text(title) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxWidth().padding(12.dp) + ) { + content() + } } } } diff --git a/sample-mpp/common/xml-images/illustrations/compose-multiplatform.xml b/sample-mpp/common/xml-images/illustrations/compose-multiplatform.xml new file mode 100644 index 0000000..9746be4 --- /dev/null +++ b/sample-mpp/common/xml-images/illustrations/compose-multiplatform.xml @@ -0,0 +1,19 @@ + + + + + + + + +