@@ -31,6 +31,7 @@ import androidx.compose.runtime.setValue
3131import androidx.compose.ui.Modifier
3232import androidx.compose.ui.text.AnnotatedString
3333import androidx.compose.ui.text.LinkAnnotation
34+ import androidx.compose.ui.text.LinkInteractionListener
3435import androidx.compose.ui.text.SpanStyle
3536import androidx.compose.ui.text.TextLayoutResult
3637import androidx.compose.ui.text.TextMeasurer
@@ -185,8 +186,9 @@ public fun BasicReadMoreText(
185186// CoreReadMoreText
186187// ////////////////////////////////////
187188
188- private const val ReadMoreTag = " read_more"
189- private const val ReadLessTag = " read_less"
189+ private const val ReadMoreTag = " readmore:read_more"
190+ private const val ReadLessTag = " readmore:read_less"
191+ private const val ContentsTag = " readmore:contents"
190192
191193@Composable
192194private fun CoreReadMoreText (
@@ -245,41 +247,27 @@ private fun CoreReadMoreText(
245247 val state = remember { ReadMoreState () }
246248
247249 val currentText = buildAnnotatedString {
248- if (expanded) {
249- append(text)
250- if (readLessTextWithStyle.isNotEmpty()) {
251- append(' ' )
252- if (toggleArea == ToggleArea .More ) {
253- withLink(
254- LinkAnnotation .Clickable (tag = ReadLessTag ) {
255- onExpandedChange?.invoke(false )
256- },
257- ) {
258- append(readLessTextWithStyle)
259- }
260- } else {
261- append(readLessTextWithStyle)
262- }
263- }
264- } else {
265- val collapsedText = state.collapsedText
266- if (collapsedText.isNotEmpty()) {
267- append(collapsedText)
268- append(overflowText)
269-
270- if (toggleArea == ToggleArea .More ) {
271- withLink(
272- LinkAnnotation .Clickable (tag = ReadMoreTag ) {
273- onExpandedChange?.invoke(true )
274- },
275- ) {
276- append(readMoreTextWithStyle)
277- }
278- } else {
279- append(readMoreTextWithStyle)
280- }
250+ withContentsLink(
251+ hasLink = onExpandedChange != null && toggleArea == ToggleArea .All
252+ && text.hasLinks() && state.isCollapsible,
253+ linkInteractionListener = { onExpandedChange?.invoke(! expanded) },
254+ ) {
255+ if (expanded) {
256+ appendExpandedText(
257+ text = text,
258+ onExpandedChange = onExpandedChange,
259+ readLessTextWithStyle = readLessTextWithStyle,
260+ toggleArea = toggleArea,
261+ )
281262 } else {
282- append(text)
263+ appendCollapsedText(
264+ text = text,
265+ collapsedText = state.collapsedText,
266+ overflowText = overflowText,
267+ onExpandedChange = onExpandedChange,
268+ readMoreTextWithStyle = readMoreTextWithStyle,
269+ toggleArea = toggleArea,
270+ )
283271 }
284272 }
285273 }
@@ -333,6 +321,77 @@ private fun CoreReadMoreText(
333321 }
334322}
335323
324+ private fun AnnotatedString.Builder.appendCollapsedText (
325+ text : AnnotatedString ,
326+ collapsedText : AnnotatedString ,
327+ overflowText : String ,
328+ onExpandedChange : ((Boolean ) -> Unit )? ,
329+ readMoreTextWithStyle : AnnotatedString ,
330+ toggleArea : ToggleArea ,
331+ ) {
332+ if (collapsedText.isNotEmpty()) {
333+ append(collapsedText)
334+ append(overflowText)
335+
336+ if (toggleArea == ToggleArea .More ) {
337+ withLink(
338+ LinkAnnotation .Clickable (tag = ReadMoreTag ) {
339+ onExpandedChange?.invoke(true )
340+ },
341+ ) {
342+ append(readMoreTextWithStyle)
343+ }
344+ } else {
345+ append(readMoreTextWithStyle)
346+ }
347+ } else {
348+ append(text)
349+ }
350+ }
351+
352+ private fun AnnotatedString.Builder.appendExpandedText (
353+ text : AnnotatedString ,
354+ onExpandedChange : ((Boolean ) -> Unit )? ,
355+ readLessTextWithStyle : AnnotatedString ,
356+ toggleArea : ToggleArea ,
357+ ) {
358+ append(text)
359+ if (readLessTextWithStyle.isNotEmpty()) {
360+ append(' ' )
361+ if (toggleArea == ToggleArea .More ) {
362+ withLink(
363+ LinkAnnotation .Clickable (tag = ReadLessTag ) {
364+ onExpandedChange?.invoke(false )
365+ },
366+ ) {
367+ append(readLessTextWithStyle)
368+ }
369+ } else {
370+ append(readLessTextWithStyle)
371+ }
372+ }
373+ }
374+
375+ private inline fun <R : Any > AnnotatedString.Builder.withContentsLink (
376+ hasLink : Boolean ,
377+ linkInteractionListener : LinkInteractionListener ? ,
378+ block : AnnotatedString .Builder .() -> R ,
379+ ): R {
380+ return if (hasLink) {
381+ withLink(
382+ LinkAnnotation .Clickable (
383+ tag = ContentsTag ,
384+ linkInteractionListener = linkInteractionListener,
385+ ),
386+ block = block,
387+ )
388+ } else {
389+ block()
390+ }
391+ }
392+
393+ private fun AnnotatedString.hasLinks () = hasLinkAnnotations(0 , length)
394+
336395// ////////////////////////////////////
337396// ReadMoreState
338397// ////////////////////////////////////
0 commit comments