Created
February 12, 2025 06:11
-
-
Save Kaaveh/e5fae0aaa1843946df1b3f90d49ab8c5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.foundation.layout.Arrangement | |
import androidx.compose.foundation.layout.Column | |
import androidx.compose.foundation.layout.Row | |
import androidx.compose.material3.Text | |
import androidx.compose.runtime.Composable | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.graphics.ColorFilter | |
import androidx.compose.ui.graphics.DefaultAlpha | |
import androidx.compose.ui.graphics.FilterQuality | |
import androidx.compose.ui.graphics.drawscope.DrawScope.Companion.DefaultFilterQuality | |
import androidx.compose.ui.layout.ContentScale | |
import androidx.compose.ui.text.TextLayoutResult | |
import androidx.compose.ui.text.TextStyle | |
import androidx.compose.ui.text.font.FontFamily | |
import androidx.compose.ui.text.font.FontStyle | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.text.style.TextAlign | |
import androidx.compose.ui.text.style.TextDecoration | |
import androidx.compose.ui.text.style.TextOverflow | |
import androidx.compose.ui.unit.TextUnit | |
import coil3.compose.AsyncImage | |
import coil3.compose.AsyncImagePainter.Companion.DefaultTransform | |
import coil3.compose.AsyncImagePainter.State | |
data class Element( | |
val type: ElementType, | |
val value: ElementValue, | |
val property: Property, | |
val children: List<Element>, | |
) | |
data class Property( | |
val borderRadius: String?, | |
val padding: String?, | |
val alignment: String?, | |
val backgroundColor: String?, | |
) | |
interface ElementValue | |
data class TextValue( | |
val text: String, | |
val modifier: Modifier = Modifier, | |
val color: Color = Color.Unspecified, | |
val fontSize: TextUnit = TextUnit.Unspecified, | |
val fontStyle: FontStyle? = null, | |
val fontWeight: FontWeight? = null, | |
val fontFamily: FontFamily? = null, | |
val letterSpacing: TextUnit = TextUnit.Unspecified, | |
val textDecoration: TextDecoration? = null, | |
val textAlign: TextAlign? = null, | |
val lineHeight: TextUnit = TextUnit.Unspecified, | |
val overflow: TextOverflow = TextOverflow.Clip, | |
val softWrap: Boolean = true, | |
val maxLines: Int = Int.MAX_VALUE, | |
val minLines: Int = 1, | |
val onTextLayout: ((TextLayoutResult) -> Unit)? = null, | |
val style: TextStyle, | |
) : ElementValue | |
data class ImageValue( | |
val imageUrl: String?, | |
val contentDescription: String?, | |
val modifier: Modifier = Modifier, | |
val transform: (State) -> State = DefaultTransform, | |
val onState: ((State) -> Unit)? = null, | |
val alignment: Alignment = Alignment.Center, | |
val contentScale: ContentScale = ContentScale.Fit, | |
val alpha: Float = DefaultAlpha, | |
val colorFilter: ColorFilter? = null, | |
val filterQuality: FilterQuality = DefaultFilterQuality, | |
val clipToBounds: Boolean = true, | |
) : ElementValue | |
data class TextInputValue( | |
val placeholder: String?, | |
val type: String?, | |
) : ElementValue { | |
enum class InputType { | |
TEXT, | |
NUMBER, | |
EMAIL, | |
PASSWORD, | |
} | |
} | |
data class ColumnValue( | |
val modifier: Modifier = Modifier, | |
val verticalArrangement: Arrangement.Vertical = Arrangement.Top, | |
val horizontalAlignment: Alignment.Horizontal = Alignment.Start, | |
) : ElementValue | |
data class RowValue( | |
val modifier: Modifier = Modifier, | |
val horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, | |
val verticalAlignment: Alignment.Vertical = Alignment.Top, | |
) : ElementValue | |
enum class ElementType(val label: String) { | |
Column("Column"), | |
Row("Row"), | |
Text("Text"), | |
Image("Image"), | |
TextInput("TextInput"), | |
Dropdown("Dropdown"), | |
} | |
object ElementRendererFactory { | |
fun getRenderer(type: ElementType): ElementRenderer { | |
return when (type) { | |
ElementType.Column -> ColumnRenderer() | |
ElementType.Row -> RowRenderer() | |
ElementType.Text -> TextRenderer() | |
ElementType.Image -> ImageRenderer() | |
ElementType.TextInput -> TODO() | |
ElementType.Dropdown -> TODO() | |
} | |
} | |
} | |
@Composable | |
fun ElementComposer( | |
element: Element, | |
) { | |
ElementRendererFactory.getRenderer(type = element.type).Render(element) | |
} | |
interface ElementRenderer { | |
@Composable | |
fun Render(element: Element) | |
} | |
class TextRenderer : ElementRenderer { | |
@Composable | |
override fun Render(element: Element) { | |
(element.value as TextValue).apply { | |
Text( | |
text = text, | |
color = color, | |
fontSize = fontSize, | |
fontStyle = fontStyle, | |
fontWeight = fontWeight, | |
fontFamily = fontFamily, | |
letterSpacing = letterSpacing, | |
textDecoration = textDecoration, | |
textAlign = textAlign, | |
lineHeight = lineHeight, | |
overflow = overflow, | |
softWrap = softWrap, | |
maxLines = maxLines, | |
minLines = minLines, | |
onTextLayout = onTextLayout, | |
style = style, | |
) | |
} | |
} | |
} | |
class ImageRenderer : ElementRenderer { | |
@Composable | |
override fun Render(element: Element) { | |
(element.value as ImageValue).apply { | |
AsyncImage( | |
model = imageUrl, | |
contentDescription = contentDescription, | |
modifier = modifier, | |
transform = transform, | |
onState = onState, | |
alignment = alignment, | |
contentScale = contentScale, | |
alpha = alpha, | |
colorFilter = colorFilter, | |
filterQuality = filterQuality, | |
clipToBounds = clipToBounds, | |
) | |
} | |
} | |
} | |
class ColumnRenderer : ElementRenderer { | |
@Composable | |
override fun Render(element: Element) { | |
(element.value as ColumnValue).apply { | |
Column( | |
modifier = modifier, | |
verticalArrangement = verticalArrangement, | |
horizontalAlignment = horizontalAlignment, | |
) { | |
element.children.forEach { element -> | |
ElementComposer(element = element) | |
} | |
} | |
} | |
} | |
} | |
class RowRenderer : ElementRenderer { | |
@Composable | |
override fun Render(element: Element) { | |
(element.value as RowValue).apply { | |
Row( | |
modifier = modifier, | |
horizontalArrangement = horizontalArrangement, | |
verticalAlignment = verticalAlignment, | |
) { | |
element.children.forEach { element -> | |
ElementComposer(element = element) | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment