Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2026-01-24 19:44:36 +01:00
padre ebc81e2bf0
commit 8dc1ea12d9
Se han modificado 2 ficheros con 41 adiciones y 15 borrados

Ver fichero

@@ -269,13 +269,13 @@ private fun formatCount(count: Int): String {
* Parse HTML content and create AnnotatedString with clickable links * Parse HTML content and create AnnotatedString with clickable links
*/ */
@Composable @Composable
private fun parseHtmlContent(html: String, linkColor: Color) = buildAnnotatedString { fun parseHtmlContent(html: String, linkColor: Color) = buildAnnotatedString {
// Convert HTML to plain text but extract links // Convert HTML to plain text but extract links
val plainText = Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT).toString() val plainText = Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT).toString()
// Regex patterns for URLs and hashtags // Regex patterns for URLs and hashtags
val urlPattern = Regex("""https?://[^\s<>"{}|\\^`\[\]]+""") val urlPattern = Regex("""https?://[^\s<>"{}|\\^`\[\]]+""")
val hashtagPattern = Regex("""(^|\s)#(\w+)""") val hashtagPattern = Regex("""#(\w+)""") // Match # and word, simpler pattern
val allMatches = mutableListOf<Pair<IntRange, String>>() val allMatches = mutableListOf<Pair<IntRange, String>>()
@@ -286,11 +286,10 @@ private fun parseHtmlContent(html: String, linkColor: Color) = buildAnnotatedStr
// Find all hashtags // Find all hashtags
hashtagPattern.findAll(plainText).forEach { match -> hashtagPattern.findAll(plainText).forEach { match ->
val hashtagRange = match.groups[2]?.range val fullHashtagRange = match.range // Include the # in the range
val hashtagValue = match.groups[2]?.value val hashtagValue = match.groups[1]?.value // Just the word without #
if (hashtagRange != null && hashtagValue != null) { if (hashtagValue != null) {
// Don't add # prefix as it's already in the text allMatches.add(fullHashtagRange to hashtagValue)
allMatches.add(hashtagRange to hashtagValue)
} }
} }
@@ -314,7 +313,12 @@ private fun parseHtmlContent(html: String, linkColor: Color) = buildAnnotatedStr
) { ) {
val tag = if (value.startsWith("http")) "URL" else "HASHTAG" val tag = if (value.startsWith("http")) "URL" else "HASHTAG"
pushStringAnnotation(tag = tag, annotation = value) pushStringAnnotation(tag = tag, annotation = value)
append(if (value.startsWith("http")) plainText.substring(range) else "#${value}") // For URLs, use the full text from range; for hashtags, add # prefix to the value
if (value.startsWith("http")) {
append(plainText.substring(range))
} else {
append("#$value")
}
pop() pop()
} }

Ver fichero

@@ -1,10 +1,13 @@
package com.manalejandro.myactivitypub.ui.screens package com.manalejandro.myactivitypub.ui.screens
import android.content.Intent
import android.net.Uri
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.filled.*
@@ -15,12 +18,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.manalejandro.myactivitypub.data.models.Status import com.manalejandro.myactivitypub.data.models.Status
import com.manalejandro.myactivitypub.data.repository.MastodonRepository import com.manalejandro.myactivitypub.data.repository.MastodonRepository
import com.manalejandro.myactivitypub.ui.components.parseHtmlContent
import com.manalejandro.myactivitypub.ui.viewmodel.StatusDetailViewModel import com.manalejandro.myactivitypub.ui.viewmodel.StatusDetailViewModel
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -113,6 +118,7 @@ fun StatusDetailScreen(
onReplyClick = onReplyClick, onReplyClick = onReplyClick,
onBoostClick = { viewModel.toggleBoost() }, onBoostClick = { viewModel.toggleBoost() },
onFavoriteClick = { viewModel.toggleFavorite() }, onFavoriteClick = { viewModel.toggleFavorite() },
onHashtagClick = onHashtagClick,
isAuthenticated = isAuthenticated isAuthenticated = isAuthenticated
) )
@@ -169,6 +175,7 @@ private fun DetailedStatusCard(
onReplyClick: (Status) -> Unit, onReplyClick: (Status) -> Unit,
onBoostClick: (Status) -> Unit, onBoostClick: (Status) -> Unit,
onFavoriteClick: (Status) -> Unit, onFavoriteClick: (Status) -> Unit,
onHashtagClick: (String) -> Unit,
isAuthenticated: Boolean isAuthenticated: Boolean
) { ) {
var selectedMedia by remember { mutableStateOf<com.manalejandro.myactivitypub.data.models.MediaAttachment?>(null) } var selectedMedia by remember { mutableStateOf<com.manalejandro.myactivitypub.data.models.MediaAttachment?>(null) }
@@ -224,13 +231,28 @@ private fun DetailedStatusCard(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
// Content // Content with clickable links and hashtags
Text( val context = LocalContext.current
text = android.text.Html.fromHtml( val annotatedContent = parseHtmlContent(status.content, MaterialTheme.colorScheme.primary)
status.content,
android.text.Html.FROM_HTML_MODE_COMPACT @Suppress("DEPRECATION")
).toString(), ClickableText(
style = MaterialTheme.typography.bodyLarge text = annotatedContent,
style = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurface),
onClick = { offset ->
// Check for URL
annotatedContent.getStringAnnotations(tag = "URL", start = offset, end = offset)
.firstOrNull()?.let { annotation ->
// Open URL in browser
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(annotation.item))
context.startActivity(intent)
}
// Check for hashtag
annotatedContent.getStringAnnotations(tag = "HASHTAG", start = offset, end = offset)
.firstOrNull()?.let { annotation ->
onHashtagClick(annotation.item)
}
}
) )
// Media attachments // Media attachments