Skip to content
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
4 changes: 2 additions & 2 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- name: set up JDK 17
- name: set up JDK 21
uses: actions/setup-java@v1
with:
java-version: 17
java-version: 21
- uses: actions/cache@v4
with:
path: ~/.gradle/caches
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 17
java-version: 21
- uses: actions/setup-python@v2
with:
python-version: 3.x
Expand Down
9 changes: 7 additions & 2 deletions android-sample/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("com.android.application")
kotlin("android")
Expand All @@ -22,8 +24,11 @@ android {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}

kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_11
}
}

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ plugins {

dependencies {
// keep in sync with Dependencies.BuildPlugins.androidGradlePlugin
implementation("com.android.tools.build:gradle:8.7.0")
implementation("com.android.tools.build:gradle:8.13.0")
// keep in sync with Dependencies.Kotlin.gradlePlugin
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.20")
implementation(kotlin("script-runtime"))
}
13 changes: 7 additions & 6 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
object BuildPlugins {
// keep in sync with buildSrc/build.gradle.kts
val androidGradlePlugin = "com.android.tools.build:gradle:8.7.0"
val androidGradlePlugin = "com.android.tools.build:gradle:8.13.0"
}

object AndroidX {
val appcompat = "androidx.appcompat:appcompat:1.3.0"
val appcompat = "androidx.appcompat:appcompat:1.7.1"
}

object Network {
Expand All @@ -13,7 +13,7 @@ object Network {

object Kotlin {
// keep in sync with buildSrc/build.gradle.kts
val version = "2.0.21"
val version = "2.2.20"
val binaryCompatibilityValidatorPlugin = "org.jetbrains.kotlinx:binary-compatibility-validator:0.9.0"
val gradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$version"

Expand All @@ -30,11 +30,12 @@ object Compose {
val desktopVersion = "1.8.2"
val activity = "androidx.activity:activity-compose:1.8.2"
val toolingData = "androidx.compose.ui:ui-tooling-data:1.6.0"
val coil = "io.coil-kt:coil-compose:2.5.0"
val coil = "io.coil-kt.coil3:coil-compose:3.3.0"
val coilHttp = "io.coil-kt.coil3:coil-network-okhttp:3.3.0"
}

object Commonmark {
private val version = "0.25.0"
private val version = "0.26.0"
val core = "org.commonmark:commonmark:$version"
val tables = "org.commonmark:commonmark-ext-gfm-tables:$version"
val strikethrough = "org.commonmark:commonmark-ext-gfm-strikethrough:$version"
Expand All @@ -43,6 +44,6 @@ object Commonmark {

object AndroidConfiguration {
val minSdk = 23
val targetSdk = 35
val targetSdk = 36
val compileSdk = targetSdk
}
8 changes: 5 additions & 3 deletions buildSrc/src/main/kotlin/richtext-android-library.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("com.android.library")
kotlin("android")
}

kotlin {
explicitApi()
compilerOptions {
jvmTarget = JvmTarget.JVM_11
}
}

android {
Expand All @@ -19,9 +24,6 @@ android {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}

buildFeatures {
compose = true
Expand Down
9 changes: 7 additions & 2 deletions buildSrc/src/main/kotlin/richtext-kmp-library.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import AndroidConfiguration.compileSdk
import AndroidConfiguration.minSdk
import AndroidConfiguration.targetSdk
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("com.android.library")
kotlin("multiplatform")
Expand All @@ -14,8 +19,8 @@ kotlin {
jvm()
androidTarget {
publishLibraryVariants("release")
compilations.all {
kotlinOptions.jvmTarget = "11"
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
explicitApi()
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
1 change: 1 addition & 0 deletions richtext-markdown/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ kotlin {
val androidMain by getting {
dependencies {
implementation(Compose.coil)
implementation(Compose.coilHttp)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import android.annotation.SuppressLint
import android.util.Base64
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.BoxWithConstraintsScope
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.size.Size
import coil3.compose.rememberAsyncImagePainter
import coil3.request.ImageRequest
import coil3.request.crossfade
import coil3.size.Size

private val DEFAULT_IMAGE_SIZE = 64.dp

Expand Down Expand Up @@ -46,39 +47,10 @@ internal actual fun MarkdownImage(
.build()
)

val density = LocalDensity.current

@SuppressLint("UnusedBoxWithConstraintsScope")
BoxWithConstraints(modifier, contentAlignment = Alignment.Center) {
val sizeModifier by remember(density, painter) {
derivedStateOf {
val painterIntrinsicSize = painter.state.painter?.intrinsicSize
if (painterIntrinsicSize != null &&
painterIntrinsicSize.isSpecified &&
painterIntrinsicSize.width != Float.POSITIVE_INFINITY &&
painterIntrinsicSize.height != Float.POSITIVE_INFINITY
) {
val width = painterIntrinsicSize.width
val height = painterIntrinsicSize.height
val scale = if (width > constraints.maxWidth) {
constraints.maxWidth.toFloat() / width
} else {
1f
}

with(density) {
Modifier.size(
(width * scale).toDp(),
(height * scale).toDp()
)
}
} else {
// if size is not defined at all, Coil fails to render the image
// here, we give a default size for images until they are loaded.
Modifier.size(DEFAULT_IMAGE_SIZE)
}
}
}
val painterState by painter.state.collectAsState()
val sizeModifier = renderInSize(painterState.painter?.intrinsicSize)

Image(
painter = painter,
Expand All @@ -88,3 +60,37 @@ internal actual fun MarkdownImage(
)
}
}

@Composable
public fun BoxWithConstraintsScope.renderInSize(
painterIntrinsicSize: androidx.compose.ui.geometry.Size?,
): Modifier {
val density = LocalDensity.current

val sizeModifier = if (painterIntrinsicSize != null &&
painterIntrinsicSize.isSpecified &&
painterIntrinsicSize.width != Float.POSITIVE_INFINITY &&
painterIntrinsicSize.height != Float.POSITIVE_INFINITY
) {
val width = painterIntrinsicSize.width
val height = painterIntrinsicSize.height
val scale = if (width > constraints.maxWidth) {
constraints.maxWidth.toFloat() / width
} else {
1f
}

with(density) {
Modifier.size(
(width * scale).toDp(),
(height * scale).toDp()
)
}
} else {
// if size is not defined at all, Coil fails to render the image
// here, we give a default size for images until they are loaded.
Modifier.size(DEFAULT_IMAGE_SIZE)
}

return sizeModifier
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public interface UnorderedMarkers {
* Creates an [UnorderedMarkers] that will cycle through the values in [markers] for each
* indentation level.
*/
public fun @Composable RichTextScope.textUnorderedMarkers(
public fun RichTextScope.textUnorderedMarkers(
vararg markers: String
): UnorderedMarkers = UnorderedMarkers {
Text(markers[it % markers.size])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ public class RichTextStringStyle(
public val codeStyle: SpanStyle? = null,
public val linkStyle: TextLinkStyles? = null
) {
public fun copy(
boldStyle: SpanStyle? = this.boldStyle,
italicStyle: SpanStyle? = this.italicStyle,
underlineStyle: SpanStyle? = this.underlineStyle,
strikethroughStyle: SpanStyle? = this.strikethroughStyle,
subscriptStyle: SpanStyle? = this.subscriptStyle,
superscriptStyle: SpanStyle? = this.superscriptStyle,
codeStyle: SpanStyle? = this.codeStyle,
linkStyle: TextLinkStyles? = this.linkStyle
): RichTextStringStyle = RichTextStringStyle(
boldStyle = boldStyle,
italicStyle = italicStyle,
underlineStyle = underlineStyle,
strikethroughStyle = strikethroughStyle,
subscriptStyle = subscriptStyle,
superscriptStyle = superscriptStyle,
codeStyle = codeStyle,
linkStyle = linkStyle
)

internal fun merge(otherStyle: RichTextStringStyle?): RichTextStringStyle {
if (otherStyle == null) return this
return RichTextStringStyle(
Expand Down