Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev -> main #205

Merged
merged 18 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Maven stuff
GROUP=com.mikepenz
VERSION_NAME=0.25.0
VERSION_CODE=2500
VERSION_NAME=0.26.0-rc02
VERSION_CODE=2600

POM_URL=https://github.com/mikepenz/multiplatform-markdown-renderer

Expand Down
20 changes: 10 additions & 10 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
[versions]
agp = "8.5.1"
agp = "8.5.2"
compileSdk = "34"
minSdk = "21"
targetSdk = "34"
androidx-activityCompose = "1.9.0"
androidx-activityCompose = "1.9.1"
androidx-material = "1.12.0"
compose = "1.6.8"
compose-plugin = "1.6.11"
kotlin = "2.0.0"
kotlin = "2.0.20"
coroutines = "1.8.1"
dokka = "1.9.20"
coil = "3.0.0-alpha08"
coil2 = "2.6.0"
aboutlib = "11.2.2"
coil = "3.0.0-alpha10"
coil2 = "2.7.0"
aboutlib = "11.2.3"
markdown = "0.7.3"
detekt = "1.23.6"
gradleMvnPublish = "0.28.0"
screenshot = "0.0.1-alpha02"
ktor = "3.0.0-wasm2"
gradleMvnPublish = "0.29.0"
screenshot = "0.0.1-alpha05"
ktor = "3.0.0-beta-2"

[libraries]
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
Expand All @@ -32,7 +32,7 @@ aboutlibraries-compose = { module = "com.mikepenz:aboutlibraries-compose-m3", ve
coil-core = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" }
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }
coil-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor", version.ref = "coil" }
coil-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }
coil2-core = { module = "io.coil-kt:coil-compose", version.ref = "coil2" }
coil2-svg = { module = "io.coil-kt:coil-svg", version.ref = "coil2" }
markdown = { module = "org.jetbrains:markdown", version.ref = "markdown" }
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
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.10-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
630 changes: 199 additions & 431 deletions kotlin-js-store/yarn.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
package com.mikepenz.markdown.coil3

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.painter.Painter
import coil3.compose.AsyncImagePainter
Expand All @@ -19,7 +13,7 @@ import com.mikepenz.markdown.model.ImageTransformer
object Coil3ImageTransformerImpl : ImageTransformer {

@Composable
override fun transform(link: String): ImageData? {
override fun transform(link: String): ImageData {
return rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalPlatformContext.current)
.data(link)
Expand All @@ -33,13 +27,9 @@ object Coil3ImageTransformerImpl : ImageTransformer {
var size by remember(painter) { mutableStateOf(painter.intrinsicSize) }
if (painter is AsyncImagePainter) {
val painterState = painter.state.collectAsState()
LaunchedEffect(painterState) {
painterState.value.painter?.let {
size = it.intrinsicSize
}
}
val intrinsicSize = painterState.value.painter?.intrinsicSize
intrinsicSize?.also { size = it }
}

return size
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ fun MarkdownImage(content: String, node: ASTNode) {
Image(
painter = imageData.painter,
contentDescription = imageData.contentDescription,
modifier = imageData.modifier,
alignment = imageData.alignment,
modifier = imageData.modifier
contentScale = imageData.contentScale,
alpha = imageData.alpha,
colorFilter = imageData.colorFilter
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,21 @@ package com.mikepenz.markdown.compose.elements

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.waitForUpOrCancellation
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.sp
import com.mikepenz.markdown.compose.LocalImageTransformer
import com.mikepenz.markdown.compose.LocalMarkdownColors
import com.mikepenz.markdown.compose.LocalMarkdownExtendedSpans
import com.mikepenz.markdown.compose.LocalMarkdownTypography
import com.mikepenz.markdown.compose.LocalReferenceLinkHandler
import com.mikepenz.markdown.compose.*
import com.mikepenz.markdown.compose.elements.material.MarkdownBasicText
import com.mikepenz.markdown.compose.extendedspans.ExtendedSpans
import com.mikepenz.markdown.compose.extendedspans.drawBehind
Expand All @@ -45,7 +39,7 @@ fun MarkdownText(
content: AnnotatedString,
modifier: Modifier = Modifier,
style: TextStyle = LocalMarkdownTypography.current.text,
extendedSpans: ExtendedSpans? = LocalMarkdownExtendedSpans.current.extendedSpans?.invoke()
extendedSpans: ExtendedSpans? = LocalMarkdownExtendedSpans.current.extendedSpans?.invoke(),
) {
// extend the annotated string with extended spans styles if provided
val extendedStyledText = if (extendedSpans != null) {
Expand Down Expand Up @@ -88,22 +82,44 @@ fun MarkdownText(

val hasUrl = content.getStringAnnotations(MARKDOWN_TAG_URL, 0, content.length).any()
val textModifier = if (hasUrl) modifier.pointerInput(Unit) {
detectTapGestures { pos ->
layoutResult.value?.let { layoutResult ->
awaitEachGesture {
val pointer = awaitFirstDown()
val pos = pointer.position // current position

val foundReference = layoutResult.value?.let { layoutResult ->
val position = layoutResult.getOffsetForPosition(pos)
content.getStringAnnotations(MARKDOWN_TAG_URL, position, position).reversed().firstOrNull()
?.let {
val foundReference = referenceLinkHandler.find(it.item)
try {
uriHandler.openUri(foundReference)
} catch (t: Throwable) {
println("Could not open the provided url: $foundReference")
}
?.let { referenceLinkHandler.find(it.item) }
}

if (foundReference != null) {
pointer.consume() // consume if we clicked on a link

val up = waitForUpOrCancellation()
if (up != null) {
up.consume()

// wait for finger up to navigate to the link
try {
uriHandler.openUri(foundReference)
} catch (t: Throwable) {
println("Could not open the provided url: $foundReference")
}
}
}
}
} else modifier


val transformer = LocalImageTransformer.current
val placeholderState by derivedStateOf {
transformer.placeholderConfig(
imageState.density,
imageState.containerSize,
imageState.intrinsicImageSize
)
}

MarkdownBasicText(
text = content,
modifier = textModifier
Expand All @@ -117,31 +133,31 @@ fun MarkdownText(
color = LocalMarkdownColors.current.text,
inlineContent = mapOf(MARKDOWN_TAG_IMAGE_URL to InlineTextContent(
Placeholder(
width = imageState.imageSize.width.sp,
height = imageState.imageSize.height.sp,
placeholderVerticalAlign = PlaceholderVerticalAlign.Bottom
width = placeholderState.size.width.sp,
height = placeholderState.size.height.sp,
placeholderVerticalAlign = placeholderState.verticalAlign
)
) { link ->
val transformer = LocalImageTransformer.current

transformer.transform(link)?.let { imageData ->
val intrinsicSize = transformer.intrinsicSize(imageData.painter)

LaunchedEffect(intrinsicSize) {
imageState.setImageSize(intrinsicSize)
}

Image(
painter = imageData.painter,
contentDescription = imageData.contentDescription,
modifier = imageData.modifier,
alignment = imageData.alignment,
modifier = imageData.modifier
contentScale = imageData.contentScale,
alpha = imageData.alpha,
colorFilter = imageData.colorFilter
)
}
}),
onTextLayout = {
layoutResult.value = it
onTextLayout?.invoke(it)
onTextLayout.invoke(it)
}
)
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,64 @@ import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.isUnspecified
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.unit.Density

interface ImageTransformer {
/**
* Will retrieve the [ImageData] from an image link/url
*/
@Composable
fun transform(link: String): ImageData?

/**
* Returns the detected intrinsic size of the painter
*/
@Composable
fun intrinsicSize(painter: Painter): Size {
return painter.intrinsicSize
}

/**
* The expected placeholderSize. Note: The same size is shared for all inline images within a single MarkdownText item.
*/
fun placeholderConfig(density: Density, containerSize: Size, intrinsicImageSize: Size): PlaceholderConfig {
return PlaceholderConfig(with(density) {
if (containerSize.isUnspecified) {
Size(180f, 180f)
} else if (intrinsicImageSize.isUnspecified) {
Size(containerSize.width.toSp().value, 180f)
} else {
val width = minOf(intrinsicImageSize.width, containerSize.width)
val height = if (intrinsicImageSize.width < containerSize.width) {
intrinsicImageSize.height
} else {
(intrinsicImageSize.height * containerSize.width) / intrinsicImageSize.width
}
Size(width.toSp().value, height.toSp().value)
}
})
}
}

@Immutable
data class PlaceholderConfig(
val size: Size,
val verticalAlign: PlaceholderVerticalAlign = PlaceholderVerticalAlign.Bottom,
)

@Immutable
data class ImageData(
val painter: Painter,
val modifier: Modifier = Modifier.fillMaxWidth(),
val contentDescription: String? = "Image",
val alignment: Alignment = Alignment.CenterStart,
val modifier: Modifier = Modifier.fillMaxWidth()
val contentScale: ContentScale = ContentScale.Fit,
val alpha: Float = DefaultAlpha,
val colorFilter: ColorFilter? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,27 @@ package com.mikepenz.markdown.model

import androidx.compose.runtime.*
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.isUnspecified
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.toSize

internal interface MarkdownImageState {
val imageSize: Size
val density: Density
val containerSize: Size
val intrinsicImageSize: Size
fun setContainerSize(intSize: IntSize)
fun setImageSize(size: Size)
}

internal class MarkdownImageStateImpl(private val density: Density) : MarkdownImageState {

private var parentSize by mutableStateOf(Size.Unspecified)

private var intrinsicImageSize by mutableStateOf(Size.Unspecified)

override val imageSize by derivedStateOf {
with(density) {
if (parentSize.isUnspecified) {
Size(180f, 180f)
} else if (intrinsicImageSize.isUnspecified) {
Size(parentSize.width.toSp().value, 180f)
} else {
val width = minOf(intrinsicImageSize.width, parentSize.width)

val height = if (intrinsicImageSize.width < parentSize.width) {
intrinsicImageSize.height
} else {
(intrinsicImageSize.height * parentSize.width) / intrinsicImageSize.width
}
Size(width.toSp().value, height.toSp().value)
}
}
}
internal class MarkdownImageStateImpl(override val density: Density) : MarkdownImageState {

override var containerSize by mutableStateOf(Size.Unspecified)

override var intrinsicImageSize by mutableStateOf(Size.Unspecified)

override fun setContainerSize(intSize: IntSize) {
parentSize = intSize.toSize()
containerSize = intSize.toSize()
}

override fun setImageSize(size: Size) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ fun AnnotatedString.Builder.buildMarkdownAnnotatedString(content: String, childr
children.forEach { child ->
if (skipIfNext == null || skipIfNext != child.type) {
if (annotator == null || !annotator(content, child)) {
val parentType = child.parent?.type
when (child.type) {
// Element types
MarkdownElementTypes.PARAGRAPH -> buildMarkdownAnnotatedString(content, child)
MarkdownElementTypes.IMAGE -> child.findChildOfTypeRecursive(
MarkdownElementTypes.LINK_DESTINATION
Expand Down Expand Up @@ -137,6 +139,8 @@ fun AnnotatedString.Builder.buildMarkdownAnnotatedString(content: String, childr
MarkdownElementTypes.INLINE_LINK -> appendMarkdownLink(content, child)
MarkdownElementTypes.SHORT_REFERENCE_LINK -> appendMarkdownLink(content, child)
MarkdownElementTypes.FULL_REFERENCE_LINK -> appendMarkdownLink(content, child)

// Token Types
MarkdownTokenTypes.TEXT -> append(child.getTextInNode(content).toString())
GFMTokenTypes.GFM_AUTOLINK -> if (child.parent == MarkdownElementTypes.LINK_TEXT) {
append(child.getTextInNode(content).toString())
Expand All @@ -154,6 +158,7 @@ fun AnnotatedString.Builder.buildMarkdownAnnotatedString(content: String, childr
MarkdownTokenTypes.EXCLAMATION_MARK -> append('!')
MarkdownTokenTypes.BACKTICK -> append('`')
MarkdownTokenTypes.HARD_LINE_BREAK -> append("\n\n")
MarkdownTokenTypes.EMPH -> if (parentType != MarkdownElementTypes.EMPH && parentType != MarkdownElementTypes.STRONG) append('*')
MarkdownTokenTypes.EOL -> append('\n')
MarkdownTokenTypes.WHITE_SPACE -> if (length > 0) {
append(' ')
Expand Down
Loading