Skip to content

Commit

Permalink
Merge pull request #149 from MohamedRejeb/1.x
Browse files Browse the repository at this point in the history
1.x
  • Loading branch information
MohamedRejeb authored Dec 4, 2023
2 parents 4920728 + cdd6ad3 commit bf99965
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 25 deletions.
10 changes: 9 additions & 1 deletion richeditor-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,19 @@ kotlin {
}

android {
namespace = "com.mohamedrejeb.richeditor"
namespace = "com.mohamedrejeb.richeditor.compose"
compileSdk = libs.versions.android.compileSdk.get().toInt()

defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
consumerProguardFile("proguard-rules.pro")
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlin {
jvmToolchain(8)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.mohamedrejeb.richeditor.model
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.style.*
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
import com.mohamedrejeb.richeditor.model.RichParagraph.Type.Companion.startText
import com.mohamedrejeb.richeditor.ui.test.getRichTextStyleTreeRepresentation
Expand All @@ -16,6 +17,9 @@ internal class RichParagraph(
var type: Type = Type.Default,
) {
interface Type {
var startTextWidth: TextUnit
get() = 0.sp
set(_) {}
val style: ParagraphStyle get() = ParagraphStyle()
val startRichSpan: RichSpan get() = RichSpan(paragraph = RichParagraph(type = this))

Expand All @@ -26,26 +30,47 @@ internal class RichParagraph(
object Default : Type

class UnorderedList : Type {
override val style: ParagraphStyle = ParagraphStyle(
textIndent = TextIndent(firstLine = 20.sp, restLine = 38.sp),

override var startTextWidth: TextUnit = 0.sp
set(value) {
field = value
style = getParagraphStyle()
}

override var style: ParagraphStyle = getParagraphStyle()

private fun getParagraphStyle() = ParagraphStyle(
textIndent = TextIndent(firstLine = (38 - startTextWidth.value).sp, restLine = 38.sp),
lineHeight = 20.sp,
)
override val startRichSpan: RichSpan = RichSpan(

override var startRichSpan: RichSpan = RichSpan(
paragraph = RichParagraph(type = this),
text = "",
)
override val nextParagraphType: Type get() = UnorderedList()

override fun copy(): Type = UnorderedList()


}

data class OrderedList(
class OrderedList(
val number: Int,
) : Type {
override val style: ParagraphStyle = ParagraphStyle(
textIndent = TextIndent(firstLine = 20.sp, restLine = 42.sp),
override var startTextWidth: TextUnit = 0.sp
set(value) {
field = value
style = getParagraphStyle()
}

override var style: ParagraphStyle = getParagraphStyle()

private fun getParagraphStyle() = ParagraphStyle(
textIndent = TextIndent(firstLine = (38 - startTextWidth.value).sp, restLine = 38.sp),
lineHeight = 20.sp,
)

override val startRichSpan: RichSpan = RichSpan(
paragraph = RichParagraph(type = this),
text = "$number. ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextIndent
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.sp
import com.mohamedrejeb.richeditor.annotation.ExperimentalRichTextApi
import com.mohamedrejeb.richeditor.model.RichParagraph.Type.Companion.startText
import com.mohamedrejeb.richeditor.parser.html.RichTextStateHtmlParser
Expand Down Expand Up @@ -64,8 +67,6 @@ class RichTextState internal constructor(

internal var singleParagraphMode by mutableStateOf(false)

internal var readOnly by mutableStateOf(false)

internal var textLayoutResult: TextLayoutResult? by mutableStateOf(null)
private set

Expand Down Expand Up @@ -147,7 +148,7 @@ class RichTextState internal constructor(
) {
richTextConfig = RichTextConfig(
linkColor = if (linkColor.isSpecified) linkColor else richTextConfig.linkColor,
linkTextDecoration = if (linkTextDecoration != null) linkTextDecoration else richTextConfig.linkTextDecoration,
linkTextDecoration = linkTextDecoration ?: richTextConfig.linkTextDecoration,
codeColor = if (codeColor.isSpecified) codeColor else richTextConfig.codeColor,
codeBackgroundColor = if (codeBackgroundColor.isSpecified) codeBackgroundColor else richTextConfig.codeBackgroundColor,
codeStrokeColor = if (codeStrokeColor.isSpecified) codeStrokeColor else richTextConfig.codeStrokeColor,
Expand Down Expand Up @@ -517,8 +518,6 @@ class RichTextState internal constructor(
* @param newTextFieldValue the new text field value.
*/
internal fun onTextFieldValueChange(newTextFieldValue: TextFieldValue) {
if (readOnly) return

tempTextFieldValue = newTextFieldValue

if (tempTextFieldValue.text.length > textFieldValue.text.length)
Expand Down Expand Up @@ -1795,8 +1794,41 @@ class RichTextState internal constructor(
}
}

internal fun onTextLayout(textLayoutResult: TextLayoutResult) {
internal fun onTextLayout(
textLayoutResult: TextLayoutResult,
density: Density,
) {
this.textLayoutResult = textLayoutResult
adjustRichParagraphLayout(
density = density,
)
}

private fun adjustRichParagraphLayout(
density: Density,
) {
var isParagraphUpdated = false

richParagraphList.toList().forEach { richParagraph ->
val type = richParagraph.type
if (!type.startRichSpan.textRange.collapsed) {
textLayoutResult?.let { textLayoutResult ->
val start = textLayoutResult.getHorizontalPosition(type.startRichSpan.textRange.min, true)
val end = textLayoutResult.getHorizontalPosition(type.startRichSpan.textRange.max, true)
val distanceSp = with(density) {
(end - start).toSp()
}

if (type.startTextWidth != distanceSp) {
type.startTextWidth = distanceSp
isParagraphUpdated = true
}
}
}
}

if (isParagraphUpdated)
updateTextFieldValue(textFieldValue)
}

internal fun getLinkByOffset(offset: Offset): String? {
Expand Down Expand Up @@ -2019,6 +2051,7 @@ class RichTextState internal constructor(
*
* @return A copy of this [RichTextState].
*/
@OptIn(ExperimentalRichTextApi::class)
fun copy(): RichTextState {
val richParagraphList = richParagraphList.map { it.copy() }
val richTextState = RichTextState(richParagraphList)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
Expand All @@ -29,6 +30,7 @@ fun BasicRichText(
minLines: Int = 1,
inlineContent: Map<String, InlineTextContent> = mapOf()
) {
val density = LocalDensity.current
val uriHandler = LocalUriHandler.current
val pointerIcon = remember {
mutableStateOf(PointerIcon.Default)
Expand Down Expand Up @@ -66,7 +68,10 @@ fun BasicRichText(
},
style = style,
onTextLayout = {
state.onTextLayout(it)
state.onTextLayout(
textLayoutResult = it,
density = density,
)
onTextLayout(it)
},
overflow = overflow,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mohamedrejeb.richeditor.ui

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
Expand All @@ -12,24 +11,24 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.LocalTextStyle
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.*
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextIndent
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.sp
import com.mohamedrejeb.richeditor.model.RichParagraph
import com.mohamedrejeb.richeditor.model.RichTextState
import kotlinx.coroutines.CoroutineScope
import kotlin.time.ExperimentalTime


/**
Expand Down Expand Up @@ -213,10 +212,6 @@ internal fun BasicRichTextEditor(
state.singleParagraphMode = singleParagraph
}

LaunchedEffect(readOnly) {
state.readOnly = readOnly
}

if (!singleParagraph) {
// Workaround for Android to fix a bug in BasicTextField where it doesn't select the correct text
// when the text contains multiple paragraphs.
Expand All @@ -242,6 +237,7 @@ internal fun BasicRichTextEditor(
BasicTextField(
value = state.textFieldValue,
onValueChange = {
if (readOnly) return@BasicTextField
if (it.text.length > maxLength) return@BasicTextField
state.onTextFieldValueChange(it)
},
Expand Down Expand Up @@ -282,7 +278,10 @@ internal fun BasicRichTextEditor(
minLines = minLines,
visualTransformation = state.visualTransformation,
onTextLayout = {
state.onTextLayout(it)
state.onTextLayout(
textLayoutResult = it,
density = density,
)
onTextLayout(it)
},
interactionSource = interactionSource,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.mohamedrejeb.richeditor.utils

internal inline fun <T> MutableList<T>.removeRange(start: Int, end: Int) {
internal fun <T> MutableList<T>.removeRange(start: Int, end: Int) {
for (i in (end - 1) downTo start) {
removeAt(i)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ fun SlackDemoContent() {
unfocusedIndicatorColor = Color.Transparent,
placeholderColor = Color.White.copy(alpha = .6f),
),
maxLength = 10,
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
Expand Down

0 comments on commit bf99965

Please sign in to comment.