Skip to content

Commit

Permalink
update html text to style tables and content padding
Browse files Browse the repository at this point in the history
  • Loading branch information
X1nto committed Jan 23, 2024
1 parent 659c3e3 commit b2d548d
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 28 deletions.
172 changes: 148 additions & 24 deletions androidApp/src/main/java/dev/xinto/argos/ui/component/HtmlText2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,29 @@ import android.annotation.SuppressLint
import android.webkit.WebView
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
Expand All @@ -32,13 +39,15 @@ fun MaterialHtmlText2(
@Language("HTML")
text: String,
modifier: Modifier = Modifier,
userScrollEnabled: Boolean = true
userScrollEnabled: Boolean = true,
contentPadding: PaddingValues = PaddingValues(0.dp),
) {
HtmlText2(
modifier = modifier,
text = text,
typography = HtmlText2Defaults.material3Typography(),
userScrollEnabled = userScrollEnabled
contentStyle = HtmlText2Defaults.material3Typography(),
userScrollEnabled = userScrollEnabled,
contentPadding = contentPadding
)
}

Expand All @@ -49,13 +58,27 @@ fun MaterialHtmlText2(
fun HtmlText2(
@Language("HTML")
text: String,
typography: HtmlText2Typography,
contentStyle: HtmlText2ContentStyle,
modifier: Modifier = Modifier,
userScrollEnabled: Boolean = true,
contentPadding: PaddingValues = PaddingValues(0.dp),
) {
val density = LocalDensity.current
val textCss = remember(density) {
typography.asCss(density)
val layoutDirection = LocalLayoutDirection.current
val textCss = remember(density, layoutDirection) {
contentStyle.asCss(density, layoutDirection)
}
val paddingCss = remember(layoutDirection) {
//li margin required to indent bullet-points
"""
body {
padding: ${contentPadding.toCss(layoutDirection)}
}
li {
margin-inline-start: ${contentPadding.calculateStartPadding(layoutDirection).value}px
}
""".trimIndent()
}
val escapedText = remember {
text.replace("#", "%23")
Expand Down Expand Up @@ -86,6 +109,7 @@ fun HtmlText2(
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
$textCss
$paddingCss
</style>
</head>
<body>
Expand Down Expand Up @@ -153,14 +177,25 @@ fun HtmlText2_Preview() {
object HtmlText2Defaults {

@Composable
fun material3Typography(color: Color = LocalContentColor.current): HtmlText2Typography {
return HtmlText2Typography(
fun material3Typography(color: Color = LocalContentColor.current): HtmlText2ContentStyle {
return HtmlText2ContentStyle(
h1 = MaterialTheme.typography.displaySmall.toHtmlTextStyle(color),
h2 = MaterialTheme.typography.headlineLarge.toHtmlTextStyle(color),
h3 = MaterialTheme.typography.headlineMedium.toHtmlTextStyle(color),
h4 = MaterialTheme.typography.headlineSmall.toHtmlTextStyle(color),
h5 = MaterialTheme.typography.titleLarge.toHtmlTextStyle(color),
body = MaterialTheme.typography.bodyLarge.toHtmlTextStyle(color)
body = MaterialTheme.typography.bodyLarge.toHtmlTextStyle(color),
a = MaterialTheme.typography.bodyLarge.toHtmlTextStyle(color = MaterialTheme.colorScheme.primary),
table = HtmlText2TableStyle(
tableCornerRadius = 16.dp,
tableContentPadding = PaddingValues(horizontal = 24.dp, vertical = 16.dp),
headerFontSize = MaterialTheme.typography.titleMedium.fontSize,
headerBackgroundColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
bodyFontSize = MaterialTheme.typography.bodyMedium.fontSize,
bodyBackgroundColor = Color.Transparent,
textAlignment = TextAlign.Center,
dividerColor = MaterialTheme.colorScheme.outlineVariant
)
)
}

Expand All @@ -174,8 +209,9 @@ object HtmlText2Defaults {
}

private interface CssRepresentable {

@Language("CSS")
fun asCss(density: Density): String
fun asCss(density: Density, layoutDirection: LayoutDirection): String
}

@Immutable
Expand All @@ -186,53 +222,141 @@ data class HtmlText2TextStyle(
) : CssRepresentable {

@Language("CSS")
override fun asCss(density: Density): String {
val (r, g, b, a) = textColor
val cssFontSize = "${fontSize.value}" + if (fontSize.isEm) "em" else "px"
override fun asCss(density: Density, layoutDirection: LayoutDirection): String {
return """
color: rgba(${r * 255f}, ${g * 255f}, ${b * 255f}, $a);
color: ${textColor.toCss()};
font-weight: ${fontWeight.weight};
font-size: $cssFontSize;
font-size: ${fontSize.toCss()};
""".trimIndent()
}
}

@Immutable
data class HtmlText2TableStyle(
val tableCornerRadius: Dp,
val tableContentPadding: PaddingValues,
val headerFontSize: TextUnit,
val headerBackgroundColor: Color,
val bodyFontSize: TextUnit,
val bodyBackgroundColor: Color,
val textAlignment: TextAlign,
val dividerColor: Color
): CssRepresentable {

@Language("CSS")
override fun asCss(density: Density, layoutDirection: LayoutDirection): String {
val cornerRadius = tableCornerRadius.toCssPx()
return """
table {
border: 0;
border-spacing: 0;
font-size: ${bodyFontSize.toCss()};
background-color: ${bodyBackgroundColor.toCss()};
}
table tr:first-child {
background-color: ${headerBackgroundColor.toCss()};
font-size: ${headerFontSize.toCss()};
}
table td {
padding: ${tableContentPadding.toCss(layoutDirection)};
text-align: ${textAlignment.toString().lowercase()};
}
table tr td {
border: 1px solid ${dividerColor.toCss()};
}
table tr:not(:last-child) td {
border-bottom: 0;
}
table tr td:not(:last-child) {
border-right: 0;
}
table tr:first-child td:first-child {
border-top-left-radius: ${cornerRadius};
}
table tr:first-child td:last-child {
border-top-right-radius: ${cornerRadius};
}
table tr:last-child td:first-child {
border-bottom-left-radius: ${cornerRadius};
}
table tr:last-child td:last-child {
border-bottom-right-radius: ${cornerRadius};
}
""".trimIndent()
}
}

@Immutable
data class HtmlText2Typography(
data class HtmlText2ContentStyle(
val h1: HtmlText2TextStyle,
val h2: HtmlText2TextStyle,
val h3: HtmlText2TextStyle,
val h4: HtmlText2TextStyle,
val h5: HtmlText2TextStyle,
val body: HtmlText2TextStyle
val body: HtmlText2TextStyle,
val a: HtmlText2TextStyle,
val table: HtmlText2TableStyle
) : CssRepresentable {

@Language("CSS")
override fun asCss(density: Density): String {
override fun asCss(density: Density, layoutDirection: LayoutDirection): String {
return """
* {
margin: 0;
padding: 0;
}
h1 {
${h1.asCss(density)}
${h1.asCss(density, layoutDirection)}
}
h2 {
${h2.asCss(density)}
${h2.asCss(density, layoutDirection)}
}
h3 {
${h3.asCss(density)}
${h3.asCss(density, layoutDirection)}
}
h4 {
${h4.asCss(density)}
${h4.asCss(density, layoutDirection)}
}
h5 {
${h5.asCss(density)}
${h5.asCss(density, layoutDirection)}
}
p, body {
${body.asCss(density)}
${body.asCss(density, layoutDirection)}
}
a {
${a.asCss(density, layoutDirection)}
}
${table.asCss(density, layoutDirection)}
""".trimIndent()
}

}

private fun Color.toCss(): String {
return "rgba(${red * 255f}, ${green * 255f}, ${blue * 255f}, $alpha)"
}

private fun TextUnit.toCss(): String {
return value.toString() + if (isEm) "em" else "px"
}

private fun Dp.toCssPx(): String {
return value.toString() + "px"
}

private fun PaddingValues.toCss(layoutDirection: LayoutDirection): String {
val topPadding = calculateTopPadding().toCssPx()
val rightPadding = calculateRightPadding(layoutDirection).toCssPx()
val bottomPadding = calculateBottomPadding().toCssPx()
val leftPadding = calculateLeftPadding(layoutDirection).toCssPx()
return "$topPadding $rightPadding $bottomPadding $leftPadding"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package dev.xinto.argos.ui.screen.course.page.syllabus

import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -87,9 +87,8 @@ fun SyllabusPage(
}
MaterialHtmlText2(
text = text,
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp)
)
}

Expand Down

0 comments on commit b2d548d

Please sign in to comment.