@@ -33,6 +33,7 @@ import androidx.compose.runtime.setValue
3333import androidx.compose.ui.Modifier
3434import androidx.compose.ui.text.AnnotatedString
3535import androidx.compose.ui.text.LinkAnnotation
36+ import androidx.compose.ui.text.LinkInteractionListener
3637import androidx.compose.ui.text.Placeholder
3738import androidx.compose.ui.text.SpanStyle
3839import androidx.compose.ui.text.TextLayoutResult
@@ -192,8 +193,9 @@ public fun BasicReadMoreText(
192193// CoreReadMoreText
193194// ////////////////////////////////////
194195
195- private const val ReadMoreTag = " read_more"
196- private const val ReadLessTag = " read_less"
196+ private const val ReadMoreTag = " readmore:read_more"
197+ private const val ReadLessTag = " readmore:read_less"
198+ private const val ContentsTag = " readmore:contents"
197199
198200@SuppressLint(" UnusedBoxWithConstraintsScope" )
199201@Composable
@@ -254,41 +256,28 @@ private fun CoreReadMoreText(
254256 val state = remember { ReadMoreState () }
255257
256258 val currentText = buildAnnotatedString {
257- if (expanded) {
258- append(text)
259- if (state.isCollapsible && readLessTextWithStyle.isNotEmpty()) {
260- append(' ' )
261- if (toggleArea == ToggleArea .More ) {
262- withLink(
263- LinkAnnotation .Clickable (tag = ReadLessTag ) {
264- onExpandedChange?.invoke(false )
265- },
266- ) {
267- append(readLessTextWithStyle)
268- }
269- } else {
270- append(readLessTextWithStyle)
271- }
272- }
273- } else {
274- val collapsedText = state.collapsedText
275- if (collapsedText.isNotEmpty()) {
276- append(collapsedText)
277- append(overflowText)
278-
279- if (toggleArea == ToggleArea .More ) {
280- withLink(
281- LinkAnnotation .Clickable (tag = ReadMoreTag ) {
282- onExpandedChange?.invoke(true )
283- },
284- ) {
285- append(readMoreTextWithStyle)
286- }
287- } else {
288- append(readMoreTextWithStyle)
289- }
259+ withContentsLink(
260+ hasLink = onExpandedChange != null && toggleArea == ToggleArea .All
261+ && text.hasLinks() && state.isCollapsible,
262+ linkInteractionListener = { onExpandedChange?.invoke(! expanded) },
263+ ) {
264+ if (expanded) {
265+ appendExpandedText(
266+ text = text,
267+ onExpandedChange = onExpandedChange,
268+ readLessTextWithStyle = readLessTextWithStyle,
269+ toggleArea = toggleArea,
270+ isCollapsible = state.isCollapsible,
271+ )
290272 } else {
291- append(text)
273+ appendCollapsedText(
274+ text = text,
275+ collapsedText = state.collapsedText,
276+ overflowText = overflowText,
277+ onExpandedChange = onExpandedChange,
278+ readMoreTextWithStyle = readMoreTextWithStyle,
279+ toggleArea = toggleArea,
280+ )
292281 }
293282 }
294283 }
@@ -345,6 +334,78 @@ private fun CoreReadMoreText(
345334 }
346335}
347336
337+ private fun AnnotatedString.Builder.appendCollapsedText (
338+ text : AnnotatedString ,
339+ collapsedText : AnnotatedString ,
340+ overflowText : String ,
341+ onExpandedChange : ((Boolean ) -> Unit )? ,
342+ readMoreTextWithStyle : AnnotatedString ,
343+ toggleArea : ToggleArea ,
344+ ) {
345+ if (collapsedText.isNotEmpty()) {
346+ append(collapsedText)
347+ append(overflowText)
348+
349+ if (toggleArea == ToggleArea .More ) {
350+ withLink(
351+ LinkAnnotation .Clickable (tag = ReadMoreTag ) {
352+ onExpandedChange?.invoke(true )
353+ },
354+ ) {
355+ append(readMoreTextWithStyle)
356+ }
357+ } else {
358+ append(readMoreTextWithStyle)
359+ }
360+ } else {
361+ append(text)
362+ }
363+ }
364+
365+ private fun AnnotatedString.Builder.appendExpandedText (
366+ text : AnnotatedString ,
367+ onExpandedChange : ((Boolean ) -> Unit )? ,
368+ readLessTextWithStyle : AnnotatedString ,
369+ toggleArea : ToggleArea ,
370+ isCollapsible : Boolean ,
371+ ) {
372+ append(text)
373+ if (isCollapsible && readLessTextWithStyle.isNotEmpty()) {
374+ append(' ' )
375+ if (toggleArea == ToggleArea .More ) {
376+ withLink(
377+ LinkAnnotation .Clickable (tag = ReadLessTag ) {
378+ onExpandedChange?.invoke(false )
379+ },
380+ ) {
381+ append(readLessTextWithStyle)
382+ }
383+ } else {
384+ append(readLessTextWithStyle)
385+ }
386+ }
387+ }
388+
389+ private inline fun <R : Any > AnnotatedString.Builder.withContentsLink (
390+ hasLink : Boolean ,
391+ linkInteractionListener : LinkInteractionListener ? ,
392+ block : AnnotatedString .Builder .() -> R ,
393+ ): R {
394+ return if (hasLink) {
395+ withLink(
396+ LinkAnnotation .Clickable (
397+ tag = ContentsTag ,
398+ linkInteractionListener = linkInteractionListener,
399+ ),
400+ block = block,
401+ )
402+ } else {
403+ block()
404+ }
405+ }
406+
407+ private fun AnnotatedString.hasLinks () = hasLinkAnnotations(0 , length)
408+
348409// ////////////////////////////////////
349410// ReadMoreState
350411// ////////////////////////////////////
0 commit comments