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

Support getting SpanStyle, RichSpanStyle and ParagraphStyle by text range. #280

Merged
merged 3 commits into from
May 19, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,94 @@ class RichTextState internal constructor(
updateTextFieldValue(textFieldValue)
}

/**
* Returns the [SpanStyle] of the text at the specified text range.
* If the text range is collapsed, the style of the character preceding the text range is returned.
*
* @param textRange the text range.
* @return the [SpanStyle] of the text at the specified text range.
*/
fun getSpanStyleByTextRange(textRange: TextRange): SpanStyle =
if (textRange.collapsed) {
val richSpan = getRichSpanByTextIndex(textIndex = textRange.min - 1)

richSpan
?.fullSpanStyle
?: RichSpanStyle.DefaultSpanStyle
} else {
val richSpanList = getRichSpanListByTextRange(textRange)

richSpanList
.getCommonStyle()
?: RichSpanStyle.DefaultSpanStyle
}

/**
* Returns the [RichSpanStyle] of the text at the specified text range.
* If the text range is collapsed, the style of the character preceding the text range is returned.
*
* @param textRange the text range.
* @return the [RichSpanStyle] of the text at the specified text range.
*/
fun getRichSpanStyleByTextRange(textRange: TextRange): RichSpanStyle =
if (textRange.collapsed) {
val richSpan = getRichSpanByTextIndex(textIndex = textRange.min - 1)

richSpan
?.fullStyle
?: RichSpanStyle.Default
} else {
val richSpanList = getRichSpanListByTextRange(textRange)

richSpanList
.getCommonRichStyle()
?: RichSpanStyle.Default
}

/**
* Returns the [ParagraphStyle] of the text at the specified text range.
* If the text range is collapsed, the style of the paragraph containing the text range is returned.
*
* @param textRange the text range.
* @return the [ParagraphStyle] of the text at the specified text range.
*/
fun getParagraphStyleByTextRange(textRange: TextRange): ParagraphStyle =
if (textRange.collapsed) {
val richParagraph = getRichParagraphByTextIndex(textIndex = textRange.min - 1)

richParagraph
?.paragraphStyle
?: RichParagraph.DefaultParagraphStyle
} else {
val richParagraphList = getRichParagraphListByTextRange(textRange)

richParagraphList
.getCommonStyle()
?: RichParagraph.DefaultParagraphStyle
}

/**
* Returns the [ParagraphType] of the text at the specified text range.
* If the text range is collapsed, the type of the paragraph containing the text range is returned.
*
* @param textRange the text range.
* @return the [ParagraphType] of the text at the specified text range.
*/
internal fun getParagraphTypeByTextRange(textRange: TextRange): ParagraphType =
if (textRange.collapsed) {
val richParagraph = getRichParagraphByTextIndex(textIndex = textRange.min - 1)

richParagraph
?.type
?: DefaultParagraph()
} else {
val richParagraphList = getRichParagraphListByTextRange(textRange)

richParagraphList
.getCommonType()
?: DefaultParagraph()
}

/**
* Toggle the [SpanStyle]
* If the passed span style doesn't exist in the [currentSpanStyle] it's going to be added.
Expand Down Expand Up @@ -2319,7 +2407,7 @@ class RichTextState internal constructor(
currentAppliedRichSpanStyle = richSpanList
.getCommonRichStyle()
?: RichSpanStyle.Default
currentAppliedSpanStyle = getRichSpanListByTextRange(selection)
currentAppliedSpanStyle = richSpanList
.getCommonStyle()
?: RichSpanStyle.DefaultSpanStyle
}
Expand Down Expand Up @@ -2357,7 +2445,6 @@ class RichTextState internal constructor(
* Updates the [currentAppliedParagraphStyle] to the [ParagraphStyle] that should be applied to the current selection.
*/
private fun updateCurrentParagraphStyle() {
currentRichParagraphType
if (selection.collapsed) {
val richParagraph = getRichParagraphByTextIndex(selection.min - 1)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package com.mohamedrejeb.richeditor.model

import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import com.mohamedrejeb.richeditor.annotation.ExperimentalRichTextApi
import com.mohamedrejeb.richeditor.paragraph.RichParagraph
import com.mohamedrejeb.richeditor.paragraph.type.DefaultParagraph
import com.mohamedrejeb.richeditor.paragraph.type.ParagraphType
import com.mohamedrejeb.richeditor.paragraph.type.UnorderedList
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
Expand Down Expand Up @@ -249,4 +254,162 @@ class RichTextStateTest {
assertEquals(richTextState.currentRichSpanStyle::class, RichSpanStyle.Code::class)
}

@Test
fun testGetSpanStyleByTextRange() {
val richTextState = RichTextState(
initialRichParagraphList = listOf(
RichParagraph(
key = 1,
).also {
it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
spanStyle = SpanStyle(fontWeight = FontWeight.Bold),
),
)

it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
),
)
}
)
)

// Get the style by text range
assertEquals(
SpanStyle(fontWeight = FontWeight.Bold),
richTextState.getSpanStyleByTextRange(TextRange(0, 4)),
)

assertEquals(
SpanStyle(),
richTextState.getSpanStyleByTextRange(TextRange(9, 19)),
)
}

@Test
fun testGetRichSpanStyleByTextRange() {
val richTextState = RichTextState(
initialRichParagraphList = listOf(
RichParagraph(
key = 1,
).also {
it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
richSpansStyle = RichSpanStyle.Code(),
),
)

it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
),
)
}
)
)

// Get the style by text range
assertEquals(
RichSpanStyle.Code(),
richTextState.getRichSpanStyleByTextRange(TextRange(0, 4)),
)

assertEquals(
RichSpanStyle.Default,
richTextState.getRichSpanStyleByTextRange(TextRange(9, 19)),
)
}

@Test
fun testGetParagraphStyleByTextRange() {
val richTextState = RichTextState(
initialRichParagraphList = listOf(
RichParagraph(
key = 1,
paragraphStyle = ParagraphStyle(
textAlign = TextAlign.Center,
),
).also {
it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
),
)
},
RichParagraph(
key = 2,
).also {
it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
),
)
}
)
)

// Get the style by text range
assertEquals(
ParagraphStyle(
textAlign = TextAlign.Center,
),
richTextState.getParagraphStyleByTextRange(TextRange(0, 4)),
)

assertEquals(
ParagraphStyle(),
richTextState.getParagraphStyleByTextRange(TextRange(19, 21)),
)
}

@Test
fun testGetParagraphTypeByTextRange() {
val richTextState = RichTextState(
initialRichParagraphList = listOf(
RichParagraph(
key = 1,
type = UnorderedList(),
).also {
it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
),
)
},
RichParagraph(
key = 2,
).also {
it.children.add(
RichSpan(
text = "Testing some text",
paragraph = it,
),
)
}
)
)

// Get the style by text range
assertEquals(
UnorderedList::class,
richTextState.getParagraphTypeByTextRange(TextRange(0, 4))::class,
)

assertEquals(
DefaultParagraph::class,
richTextState.getParagraphTypeByTextRange(TextRange(19, 21))::class,
)
}

}
Loading