Compare commits

..
2 Commits
Author SHA1 Message Date
Amirmahdi dd5cbaa3bc feat: clean text 2026-05-27 20:42:39 +03:30
Amirmahdi e65c699bcb feat: clean text 2026-05-27 20:42:16 +03:30
2 changed files with 218 additions and 134 deletions
@@ -535,23 +535,94 @@ class DrugDetailParser {
* Converts block elements to newlines for better readability.
*/
private fun cleanText(element: Element): String {
// Clone to avoid affecting the original
val clone = element.clone()
val output = StringBuilder()
// Replace block-level elements with newlines for structure
clone.select("p, div, h2, h3, h4, li, br").before("\n")
// Process all nodes in order (both elements and text nodes)
processNode(clone, output)
// Get the text and clean it up
var text = clone.text()
.replace(Regex("\\n\\s*\\n+"), "\n\n") // Collapse multiple newlines
.replace(Regex("[ \\t]+"), " ") // Collapse spaces/tabs
return output.toString()
.replace(Regex("\\n{3,}"), "\n\n") // Collapse 3+ newlines to 2
.trim()
// Ensure lists look decent
if (element.tagName() == "li") {
text = "$text"
}
return text
/**
* Recursively process nodes to build formatted text
*/
private fun processNode(node: org.jsoup.nodes.Node, output: StringBuilder) {
when (node) {
is Element -> {
when (node.tagName()) {
"h2" -> {
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append("\n\n📌 $text\n\n")
output.append("".repeat(minOf(30, text.length))).append("\n\n")
}
}
"h3" -> {
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append("\n\n🔹 $text\n\n")
}
}
"h4" -> {
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append("\n$text\n")
}
}
"p" -> {
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append(text).append("\n\n")
}
}
"ul", "ol" -> {
for (li in node.select("li")) {
val liText = li.text().trim()
if (liText.isNotEmpty()) {
output.append("$liText\n")
}
}
output.append("\n")
}
"li" -> {
// Handled by ul/ol processing, but if standalone:
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append("$text\n")
}
}
"br" -> {
output.append("\n")
}
"strong", "b" -> {
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append("**$text**")
}
}
"div", "section", "article" -> {
// Process children of container elements
for (child in node.childNodes()) {
processNode(child, output)
}
}
else -> {
// For other elements, just process their children
for (child in node.childNodes()) {
processNode(child, output)
}
}
}
}
is org.jsoup.nodes.TextNode -> {
val text = node.text().trim()
if (text.isNotEmpty()) {
output.append(text)
}
}
}
}
}
@@ -25,12 +25,14 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
@@ -39,8 +41,10 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -70,6 +74,7 @@ fun DrugDetailScreen(
viewModel.loadDrugDetail(detailUrl)
}
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
Scaffold(
topBar = {
TopAppBar(
@@ -93,6 +98,7 @@ fun DrugDetailScreen(
}
}
}
else -> {
Text("جزئیات دارو", fontSize = 16.sp)
}
@@ -148,7 +154,10 @@ fun DrugDetailScreen(
ManufacturerInfoCard(
manufacturer = drugDetail.manufacturer!!,
genericInfo = drugDetail.genericInfo,
modifier = Modifier.padding(horizontal = dime.md, vertical = dime.sm)
modifier = Modifier.padding(
horizontal = dime.md,
vertical = dime.sm
)
)
}
@@ -186,12 +195,15 @@ fun DrugDetailScreen(
0 -> {
item { GeneralInfoTabContent(drugDetail) }
}
1 -> {
item { SpecializedInfoTabContent(drugDetail) }
}
2 -> {
item { DosageFormsTabContent(drugDetail) }
}
3 -> {
item { BrandNamesTabContent(drugDetail) }
}
@@ -214,6 +226,7 @@ fun DrugDetailScreen(
}
}
}
}
}
@Composable