From 2c1ec48bd387667199b7376531f7364c79880223 Mon Sep 17 00:00:00 2001 From: Nicolas Roard Date: Wed, 21 Jul 2021 12:08:37 -0700 Subject: [PATCH 1/2] Add support for user-customizable design elements --- .../compose/ConstraintLayout.kt | 94 +++++++++++++------ .../compose/ConstraintSetParser.kt | 19 +++- .../example/constraintlayout/MainActivity.kt | 34 +++++++ 3 files changed, 111 insertions(+), 36 deletions(-) diff --git a/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt b/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt index 672016123..db6c35ef9 100644 --- a/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt +++ b/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt @@ -22,29 +22,29 @@ import android.os.Looper import android.util.Log import androidx.annotation.FloatRange import androidx.compose.foundation.Canvas -//import androidx.compose.foundation.Image +import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.LayoutScopeMarker -//import androidx.compose.material.Button -//import androidx.compose.material.Text +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicText +import androidx.compose.foundation.text.BasicTextField import androidx.compose.runtime.* import androidx.compose.runtime.snapshots.SnapshotStateObserver import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.* import androidx.compose.ui.platform.InspectorValueInfo import androidx.compose.ui.platform.debugInspectorInfo +import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.unit.Constraints -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntOffset -import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.* import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed import androidx.constraintlayout.core.parser.CLKey @@ -63,7 +63,6 @@ import androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviou import androidx.constraintlayout.core.widgets.analyzer.BasicMeasure import androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure.TRY_GIVEN_DIMENSIONS import androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure.USE_GIVEN_DIMENSIONS -//import com.google.accompanist.coil.rememberCoilPainter import org.intellij.lang.annotations.Language import java.lang.StringBuilder import java.util.* @@ -1567,7 +1566,7 @@ open class EditableJSONLayout(@Language("json5") content: String) : } } -data class DesignElement(var id: String, var type: String, var param: String) +data class DesignElement(var id: String, var type: String, var params: HashMap) class JSONConstraintSet(@Language("json5") content: String, @Language("json5") overrideVariables: String? = null) @@ -2183,27 +2182,53 @@ internal open class Measurer : BasicMeasure.Measurer, DesignInfoProvider { fun createDesignElements() { for (element in designElements) { var id = element.id - when (element.type) { - /* // commenting for now until we provide hooks - "button" -> { - Button( - modifier = Modifier.layoutId(id), - onClick = {}, - ) { - Text(text = element.param) + var function = DesignElements.map[element.type] + if (function != null) { + function(id, element.params) + } else { + when (element.type) { + "button" -> { + val text = element.params["text"] ?: "text" + var style = TextStyle.Default + val fontSizeString = element.params["size"] + if (fontSizeString != null) { + val fontSize = fontSizeString.toFloat().sp + style = TextStyle(fontSize = fontSize) + } + BasicText(modifier = Modifier + .layoutId(id) + .clip(RoundedCornerShape(20)) + .background(Color.LightGray) + .padding(8.dp), + text = text, style = style) + } + "text" -> { + val text = element.params["text"] ?: "text" + var style = TextStyle.Default + val fontSizeString = element.params["size"] + if (fontSizeString != null) { + val fontSize = fontSizeString.toFloat().sp + style = TextStyle(fontSize = fontSize) + } + BasicText(modifier = Modifier.layoutId(id), + text = text, style = style) + } + "textfield" -> { + val text = element.params["text"] ?: "text" + BasicTextField( + modifier = Modifier.layoutId(id), + value = text, + onValueChange = {} + ) + } + "image" -> { + Image( + modifier = Modifier.layoutId(id), + painter = painterResource(id = android.R.drawable.ic_menu_gallery), + contentDescription = "Placeholder Image" + ) } } - "text" -> { - Text(modifier = Modifier.layoutId(id), - text=element.param) - } - "image" -> { - Image(modifier = Modifier.layoutId(id), - painter = rememberCoilPainter(element.param), - contentDescription = "" - ) - } - */ } } } @@ -2215,6 +2240,13 @@ internal open class Measurer : BasicMeasure.Measurer, DesignInfoProvider { } } +object DesignElements { + var map = HashMap) -> Unit >() + fun define(name: String, function : @Composable (String, HashMap) -> Unit) { + map[name] = function + } +} + internal fun buildMapping(state: State, measurables: List) { measurables.fastForEach { measurable -> val parentData = measurable.parentData as? ConstraintLayoutParentData diff --git a/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintSetParser.kt b/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintSetParser.kt index 82332ad69..a3f78cf91 100644 --- a/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintSetParser.kt +++ b/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintSetParser.kt @@ -695,11 +695,20 @@ fun parseDesignElementsJSON(content: String, list: ArrayList) { val element = element.get(elementName) as CLObject System.out.printf("element found <$elementName>") val type = element.getStringOrNull("type") - val param = element.getStringOrNull("param") - val text = element.getStringOrNull("text") - val parameter = if (param != null) param else text - var designElement = DesignElement(elementName, type, parameter) - list.add(designElement) + if (type != null) { + var parameters = HashMap() + val size = element.size() + for (j in 0.. size -1) { + val key = element[j] as CLKey + val paramName = key.content() + val paramValue = key.value?.content() + if (paramValue != null) { + parameters[paramName] = paramValue + } + } + var designElement = DesignElement(elementName, type, parameters) + list.add(designElement) + } } } } diff --git a/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt b/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt index d4389e808..924bab652 100644 --- a/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt +++ b/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt @@ -5,10 +5,16 @@ import android.view.View import android.widget.FrameLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.Image +import androidx.compose.material.Button +import androidx.compose.material.Text import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.ComposeView import androidx.constraintlayout.compose.* import androidx.constraintlayout.coreAndroid.PhoneState +import com.google.accompanist.coil.rememberCoilPainter class MainActivity : AppCompatActivity() { private var mFrameLayout: FrameLayout? = null @@ -29,9 +35,37 @@ class MainActivity : AppCompatActivity() { map.put(30, "Cycle RotationZ") map.put(31, "Cycle RotationXY") + defineDesignElements() debugServer.start() } + private fun defineDesignElements() { + DesignElements.define("wow") { + id, params -> + val text = params["text"] ?: "text" + Text(modifier = Modifier.layoutId(id), + text= text) + } + DesignElements.define("button") { + id, params -> + val text = params["text"] ?: "text" + Button(modifier = Modifier.layoutId(id), + onClick = {}, + ) { + Text(text = text) + } + } + DesignElements.define("image") { + id, params -> + val url = params["url"] ?: "url" + val description = params["description"] ?: "Image Description" + Image(modifier = Modifier.layoutId(id), + painter = rememberCoilPainter(url), + contentDescription = description + ) + } + } + @ExperimentalMaterialApi private fun show(com: ComposeView) { println(" $composeNum ") From a8c2ae06996ea6b9d199a4dccc3aa4b8c647dfe3 Mon Sep 17 00:00:00 2001 From: Nicolas Roard Date: Wed, 21 Jul 2021 12:42:15 -0700 Subject: [PATCH 2/2] Add box --- .../compose/ConstraintLayout.kt | 55 ++++++++++++++----- .../example/constraintlayout/MainActivity.kt | 8 +-- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt b/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt index db6c35ef9..ba24e15d2 100644 --- a/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt +++ b/constraintlayout/compose/src/main/java/androidx/constraintlayout/compose/ConstraintLayout.kt @@ -2178,6 +2178,32 @@ internal open class Measurer : BasicMeasure.Measurer, DesignInfoProvider { private var designElements = arrayListOf() + + private fun getColor(str: String?, defaultColor: Color = Color.Black) : Color { + if (str != null && str.startsWith('#')) { + var str2 = str.substring(1) + if(str2.length == 6) { + str2 = "FF$str2" + } + try { + return Color(java.lang.Long.parseLong(str2, 16).toInt()) + } catch (e: Exception) { + return defaultColor + } + } + return defaultColor + } + + private fun getTextStyle(params: HashMap) : TextStyle { + val fontSizeString = params["size"] + var fontSize = TextUnit.Unspecified + if (fontSizeString != null) { + fontSize = fontSizeString.toFloat().sp + } + var textColor = getColor(params["color"]) + return TextStyle(fontSize = fontSize, color = textColor) + } + @Composable fun createDesignElements() { for (element in designElements) { @@ -2189,29 +2215,28 @@ internal open class Measurer : BasicMeasure.Measurer, DesignInfoProvider { when (element.type) { "button" -> { val text = element.params["text"] ?: "text" - var style = TextStyle.Default - val fontSizeString = element.params["size"] - if (fontSizeString != null) { - val fontSize = fontSizeString.toFloat().sp - style = TextStyle(fontSize = fontSize) - } + val colorBackground = getColor(element.params["backgroundColor"], Color.LightGray) BasicText(modifier = Modifier .layoutId(id) .clip(RoundedCornerShape(20)) - .background(Color.LightGray) + .background(colorBackground) .padding(8.dp), - text = text, style = style) + text = text, style = getTextStyle(element.params)) + } + "box" -> { + val text = element.params["text"] ?: "" + val colorBackground = getColor(element.params["backgroundColor"], Color.LightGray) + Box(modifier = Modifier.layoutId(id).background(colorBackground)) { + BasicText( + modifier = Modifier.padding(8.dp), + text = text, style = getTextStyle(element.params) + ) + } } "text" -> { val text = element.params["text"] ?: "text" - var style = TextStyle.Default - val fontSizeString = element.params["size"] - if (fontSizeString != null) { - val fontSize = fontSizeString.toFloat().sp - style = TextStyle(fontSize = fontSize) - } BasicText(modifier = Modifier.layoutId(id), - text = text, style = style) + text = text, style = getTextStyle(element.params)) } "textfield" -> { val text = element.params["text"] ?: "text" diff --git a/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt b/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt index 924bab652..3a3d9f241 100644 --- a/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt +++ b/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/MainActivity.kt @@ -18,7 +18,7 @@ import com.google.accompanist.coil.rememberCoilPainter class MainActivity : AppCompatActivity() { private var mFrameLayout: FrameLayout? = null - private var composeNum = 39 + private var composeNum = 38 private var MAX = 39 var map = HashMap(); @@ -40,13 +40,13 @@ class MainActivity : AppCompatActivity() { } private fun defineDesignElements() { - DesignElements.define("wow") { + DesignElements.define("text-material") { id, params -> val text = params["text"] ?: "text" Text(modifier = Modifier.layoutId(id), text= text) } - DesignElements.define("button") { + DesignElements.define("button-material") { id, params -> val text = params["text"] ?: "text" Button(modifier = Modifier.layoutId(id), @@ -55,7 +55,7 @@ class MainActivity : AppCompatActivity() { Text(text = text) } } - DesignElements.define("image") { + DesignElements.define("image-coil") { id, params -> val url = params["url"] ?: "url" val description = params["description"] ?: "Image Description"