From 43427ae420bb9a5ea3b501e401cf84dd91e6e246 Mon Sep 17 00:00:00 2001 From: Amirmahdi Nourkazemi Date: Fri, 5 Jun 2026 01:36:57 +0330 Subject: [PATCH] style: make better style --- .idea/codeStyles/Project.xml | 157 ++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/compiler.xml | 2 +- .idea/misc.xml | 3 +- .idea/vcs.xml | 2 +- .../drug/data/remote/PharmacyHtmlParser.kt | 66 ++++- .../components/PharmacyBottomSheet.kt | 231 ++++++++++-------- 7 files changed, 348 insertions(+), 118 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..9c3d95a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 8fabff5..8b3f102 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index d7916a5..a4f09e2 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ + - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 9661ac7..c8397c9 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/src/main/java/com/approagency/drug/data/remote/PharmacyHtmlParser.kt b/app/src/main/java/com/approagency/drug/data/remote/PharmacyHtmlParser.kt index 011073e..00db616 100644 --- a/app/src/main/java/com/approagency/drug/data/remote/PharmacyHtmlParser.kt +++ b/app/src/main/java/com/approagency/drug/data/remote/PharmacyHtmlParser.kt @@ -1,4 +1,5 @@ package com.approagency.drug.data.remote + import com.approagency.drug.domain.model.PharmacyItem import org.jsoup.Jsoup @@ -7,31 +8,48 @@ object PharmacyHtmlParser { fun parse(html: String): List { val items = mutableListOf() val doc = Jsoup.parse(html) - val rows = doc.select("table#TBL_patientReferral tbody tr") + val table = doc.select("table#TBL_patientReferral").first() ?: return emptyList() + + // تشخیص ساختار بر اساس سربرگ جدول (یک بار برای کل جدول) + val hasGuaranteeColumn = hasGuaranteeColumnInHeader(table) + + val rows = table.select("tbody tr") for (row in rows) { val cells = row.select("td") if (cells.size < 3) continue - // ستون 0: اطلاعات برند - val brandCell = cells[0] + // ایندکس ستون‌ها بر اساس وجود ستون تضمین + val brandIndex = if (hasGuaranteeColumn) 1 else 0 + val pharmacyIndex = if (hasGuaranteeColumn) 2 else 1 + val locationIndex = if (hasGuaranteeColumn) 3 else 2 + + // ستون برند + val brandCell = cells[brandIndex] val brandLink = brandCell.select("a").first() val brandName = brandLink?.text()?.trim() ?: "" val brandUrl = brandLink?.attr("href")?.trim() ?: "" val brandId = extractIdFromUrl(brandUrl, "/B-(\\d+)/?") - // ستون 1: اطلاعات داروخانه - val pharmacyCell = cells[1] - val pharmacyLink = pharmacyCell.select("a").first() + // ستون داروخانه + val pharmacyCell = cells[pharmacyIndex] + val pharmacyLinks = pharmacyCell.select("a") + + // پیدا کردن لینک داروخانه (لینکی که "اطلاعات تماس" نباشد) + val pharmacyLink = pharmacyLinks.firstOrNull { + !it.text().contains("اطلاعات تماس") + } val pharmacyName = pharmacyLink?.text()?.trim() ?: "" val pharmacyUrl = pharmacyLink?.attr("href")?.trim() ?: "" val pharmacyId = extractIdFromUrl(pharmacyUrl, "/ph-(\\d+)/?") - // ستون 2: موقعیت - val locationText = cells[2].text().trim() - val parts = locationText.split("شهر") - val province = parts.getOrNull(0)?.replace("استان", "")?.trim() ?: "" - val city = parts.getOrNull(1)?.trim() ?: "" + // ستون موقعیت + val locationCell = cells[locationIndex] + val locationText = locationCell.text().trim() + + // استخراج استان و شهر + val province = extractProvince(locationText) + val city = extractCity(locationText) if (brandName.isNotBlank() && pharmacyName.isNotBlank()) { items.add( @@ -52,6 +70,32 @@ object PharmacyHtmlParser { return items } + /** + * تشخیص وجود ستون تضمین موجودی با بررسی سربرگ جدول + */ + private fun hasGuaranteeColumnInHeader(table: org.jsoup.nodes.Element): Boolean { + val headers = table.select("thead th") + if (headers.isEmpty()) return false + + // بررسی می‌کنیم که آیا اولین ستون حاوی متن "تضمین" است + val firstHeaderText = headers.firstOrNull()?.text()?.trim() ?: "" + return firstHeaderText.contains("تضمین") || firstHeaderText.contains("موجودی") + } + + private fun extractProvince(locationText: String): String { + // الگو: "استان تهران" یا "استان اصفهان" + val provincePattern = "استان\\s*(\\S+)".toRegex() + val match = provincePattern.find(locationText) + return match?.groupValues?.get(1)?.trim() ?: "" + } + + private fun extractCity(locationText: String): String { + // الگو: "شهر تهران" یا "شهر اصفهان" یا "شهر پردیس" + val cityPattern = "شهر\\s*(.+)".toRegex() + val match = cityPattern.find(locationText) + return match?.groupValues?.get(1)?.trim() ?: "" + } + private fun extractIdFromUrl(url: String, pattern: String): String { val regex = pattern.toRegex() return regex.find(url)?.groupValues?.get(1) ?: "" diff --git a/app/src/main/java/com/approagency/drug/presentation/components/PharmacyBottomSheet.kt b/app/src/main/java/com/approagency/drug/presentation/components/PharmacyBottomSheet.kt index 70ea88c..2b3eed8 100644 --- a/app/src/main/java/com/approagency/drug/presentation/components/PharmacyBottomSheet.kt +++ b/app/src/main/java/com/approagency/drug/presentation/components/PharmacyBottomSheet.kt @@ -1,6 +1,7 @@ package com.approagency.drug.presentation.components +import android.annotation.SuppressLint import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -8,6 +9,7 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.LayoutDirection @@ -15,12 +17,15 @@ import androidx.compose.ui.unit.dp import com.approagency.drug.domain.model.PharmacyItem import com.approagency.drug.presentation.common.CustomBox import com.approagency.drug.presentation.common.CustomModalBottomSheet +import com.approagency.drug.presentation.common.Loading import com.approagency.drug.presentation.viewModel.PharmacyState import com.approagency.drug.presentation.viewModel.PharmacyViewModel import com.approagency.drug.utils.provinces import com.vada.caller.ui.theme.LocalDime +import com.vada.caller.ui.theme.dime import kotlinx.coroutines.launch +@SuppressLint("ConfigurationScreenWidthHeight") @OptIn(ExperimentalMaterial3Api::class) @Composable fun PharmacyBottomSheet( @@ -55,135 +60,153 @@ fun PharmacyBottomSheet( scope = scope ) { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) + LazyColumn( + modifier = Modifier.fillMaxHeight() + .fillMaxWidth().heightIn(min = 400.dp) + .padding(MaterialTheme.dime.md), + verticalArrangement = Arrangement.spacedBy(MaterialTheme.dime.xl) ) { - // عنوان - Text( - text = "جستجوی دارو در داروخانه‌ها", - fontWeight = FontWeight.Bold, - fontSize = MaterialTheme.typography.titleMedium.fontSize - ) - - // انتخاب استان - ExposedDropdownMenuBox( - expanded = showProvinceDropdown, - onExpandedChange = { showProvinceDropdown = it } - ) { - OutlinedTextField( - value = provinces.find { it.id == selectedProvinceId }?.name - ?: "انتخاب استان", - onValueChange = {}, - readOnly = true, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = showProvinceDropdown) }, - modifier = Modifier - .fillMaxWidth() - .menuAnchor(), - shape = MaterialTheme.shapes.large + item { + Text( + text = "جستجوی دارو در داروخانه‌ها", + fontWeight = FontWeight.Bold, + fontSize = MaterialTheme.typography.titleMedium.fontSize ) - - ExposedDropdownMenu( - expanded = showProvinceDropdown, - onDismissRequest = { showProvinceDropdown = false } - ) { - provinces.forEach { province -> - DropdownMenuItem( - text = { Text(province.name) }, - onClick = { - selectedProvinceId = province.id - showProvinceDropdown = false - // جستجو با استان جدید - viewModel.search(genericDrugId, province.id) - } - ) - } - } } + // عنوان - Spacer(modifier = Modifier.height(8.dp)) - - // نمایش نتایج - when (val state = pharmacyState) { - PharmacyState.Loading -> { - Box( + item { + ExposedDropdownMenuBox( + expanded = showProvinceDropdown, + onExpandedChange = { showProvinceDropdown = it } + ) { + OutlinedTextField( + value = provinces.find { it.id == selectedProvinceId }?.name + ?: "انتخاب استان", + onValueChange = {}, + readOnly = true, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = showProvinceDropdown) }, modifier = Modifier .fillMaxWidth() - .height(200.dp), - contentAlignment = Alignment.Center + .menuAnchor(), + shape = MaterialTheme.shapes.large + ) + + ExposedDropdownMenu( + expanded = showProvinceDropdown, + onDismissRequest = { showProvinceDropdown = false } ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator( - modifier = Modifier.size(32.dp) - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = "در حال جستجو...", - fontSize = MaterialTheme.typography.bodySmall.fontSize + provinces.forEach { province -> + DropdownMenuItem( + text = { Text(province.name) }, + onClick = { + selectedProvinceId = province.id + showProvinceDropdown = false + // جستجو با استان جدید + viewModel.search(genericDrugId, province.id) + } ) } } } + } + // انتخاب استان + + + + + // نمایش نتایج + when (val state = pharmacyState) { + PharmacyState.Loading -> { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .height(400.dp), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Loading() + Spacer(modifier = Modifier.height(MaterialTheme.dime.xl)) + Text( + text = "در حال جستجو...", + fontSize = MaterialTheme.typography.bodySmall.fontSize + ) + } + } + } + + } is PharmacyState.Success -> { if (state.items.isEmpty()) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .height(400.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "هیچ داروخانه‌ای یافت نشد", + fontSize = MaterialTheme.typography.bodyMedium.fontSize, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) + ) + } + } + + } else { + items(state.items) + { pharmacy -> + PharmacyResultItem(pharmacy = pharmacy) + } + item { + Spacer(modifier = Modifier.height(MaterialTheme.dime.md)) + Text( + text = "تعداد کل: ${state.items.size} داروخانه", + fontSize = MaterialTheme.typography.bodySmall.fontSize, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f), + modifier = Modifier.padding(bottom = MaterialTheme.dime.xs) + ) + } +// LazyColumn( +// verticalArrangement = Arrangement.spacedBy(8.dp), +// modifier = Modifier, +// ) { +// items(state.items) { pharmacy -> +// PharmacyResultItem(pharmacy = pharmacy) +// } +// +// +// } + + } + } + + is PharmacyState.Error -> { + item { Box( modifier = Modifier .fillMaxWidth() .height(200.dp), contentAlignment = Alignment.Center ) { - Text( - text = "هیچ داروخانه‌ای یافت نشد", - fontSize = MaterialTheme.typography.bodyMedium.fontSize, - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) - ) - } - } else { - LazyColumn( - verticalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.weight(1f), - ) { - items(state.items) { pharmacy -> - PharmacyResultItem(pharmacy = pharmacy) - } - - item { - Spacer(modifier = Modifier.height(16.dp)) + Column(horizontalAlignment = Alignment.CenterHorizontally) { Text( - text = "تعداد کل: ${state.items.size} داروخانه", - fontSize = MaterialTheme.typography.bodySmall.fontSize, - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f), - modifier = Modifier.padding(bottom = 8.dp) + text = state.message, + color = MaterialTheme.colorScheme.error, + fontSize = MaterialTheme.typography.bodyMedium.fontSize ) + Spacer(modifier = Modifier.height(8.dp)) + TextButton( + onClick = { viewModel.retry() } + ) { + Text("تلاش مجدد") + } } } } - } - is PharmacyState.Error -> { - Box( - modifier = Modifier - .fillMaxWidth() - .height(200.dp), - contentAlignment = Alignment.Center - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = state.message, - color = MaterialTheme.colorScheme.error, - fontSize = MaterialTheme.typography.bodyMedium.fontSize - ) - Spacer(modifier = Modifier.height(8.dp)) - TextButton( - onClick = { viewModel.retry() } - ) { - Text("تلاش مجدد") - } - } - } } PharmacyState.Idle -> {} @@ -201,7 +224,7 @@ fun PharmacyResultItem( ) { val dime = LocalDime.current - CustomBox ( + CustomBox( modifier = modifier.fillMaxWidth(), ) { Column(