diff --git a/app/src/main/java/com/approagency/pharmacy/di/AppModule.kt b/app/src/main/java/com/approagency/pharmacy/di/AppModule.kt index ecc7d49..c0299ce 100644 --- a/app/src/main/java/com/approagency/pharmacy/di/AppModule.kt +++ b/app/src/main/java/com/approagency/pharmacy/di/AppModule.kt @@ -24,7 +24,7 @@ import com.approagency.pharmacy.presentation.viewModel.HomeViewModel import com.approagency.pharmacy.presentation.viewModel.LabViewModel import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel import com.approagency.pharmacy.utils.Config -import com.approgency.drug.presentation.viewModel.SearchViewModel +import com.approagency.pharmacy.presentation.viewModel.SearchViewModel import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import org.koin.android.ext.koin.androidContext diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyBottomSheet.kt b/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyBottomSheet.kt index 5b3a87c..1348522 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyBottomSheet.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyBottomSheet.kt @@ -6,9 +6,6 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.LocationOn -import androidx.compose.material.icons.filled.Phone import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -17,16 +14,11 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.approagency.pharmacy.domain.model.PharmacyItem -import com.approagency.pharmacy.presentation.common.CustomBox import com.approagency.pharmacy.presentation.common.CustomModalBottomSheet import com.approagency.pharmacy.presentation.common.Loading -import com.approagency.pharmacy.presentation.viewModel.PharmacyDetailState import com.approagency.pharmacy.presentation.viewModel.PharmacyState import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel import com.approagency.pharmacy.utils.provinces -import com.vada.caller.ui.theme.LocalDime import com.vada.caller.ui.theme.dime @SuppressLint("ConfigurationScreenWidthHeight") @@ -199,145 +191,3 @@ fun PharmacyBottomSheet( } } } - -@Composable -fun PharmacyResultItem( - pharmacy: PharmacyItem, viewModel: PharmacyViewModel, modifier: Modifier = Modifier -) { - val dime = LocalDime.current - var showDetails by remember { mutableStateOf(false) } - // گرفتن State مخصوص این داروخانه از Map - val detailStates by viewModel.pharmacyDetailStates.collectAsState() - val detailState = detailStates[pharmacy.pharmacyUrl] ?: PharmacyDetailState.Idle - - // Reset detail state when item changes - LaunchedEffect(pharmacy.pharmacyUrl) { - println(pharmacy.pharmacyUrl) - showDetails = false - } - - // Load detail when expanded - LaunchedEffect(showDetails) { - if (showDetails) { - // فقط اگر Idle هست (هنوز لود نشده) درخواست بده - if (detailState is PharmacyDetailState.Idle) { - println(pharmacy.pharmacyUrl) - viewModel.loadPharmacyDetail(pharmacy.pharmacyUrl) - } - } - } - CustomBox( - modifier = modifier.fillMaxWidth(), - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(dime.md), - verticalArrangement = Arrangement.spacedBy(dime.xs) - ) { - // نام برند - Text( - text = pharmacy.brandName, - fontSize = MaterialTheme.typography.labelSmall.fontSize, - color = MaterialTheme.colorScheme.primary - ) - - // نام داروخانه - Text( - text = pharmacy.pharmacyName, - fontWeight = FontWeight.Bold, - fontSize = MaterialTheme.typography.labelLarge.fontSize - ) - - // موقعیت - // موقعیت و دکمه اطلاعات تماس - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() - ) { - Text( - text = "${pharmacy.province} - ${pharmacy.city}", - fontSize = MaterialTheme.typography.bodySmall.fontSize, - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) - ) - - TextButton( - onClick = { showDetails = !showDetails }) { - Text( - text = if (showDetails) "بستن" else "اطلاعات تماس", - fontSize = MaterialTheme.typography.bodySmall.fontSize - ) - } - } - if (showDetails) { - - when (detailState) { - is PharmacyDetailState.Loading -> { - Row( - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth() - ) { - Loading(size = 24.dp) - } - } - - is PharmacyDetailState.Success -> { - Column( - verticalArrangement = Arrangement.spacedBy(dime.sm) - ) { - HorizontalDivider(modifier = Modifier.padding(vertical = MaterialTheme.dime.xs)) - // آدرس - Row( - verticalAlignment = Alignment.Top, - horizontalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Icon( - imageVector = Icons.Default.LocationOn, - contentDescription = null, - modifier = Modifier.size(16.dp), - tint = MaterialTheme.colorScheme.primary - ) - Text( - text = detailState.detail.address, - fontSize = MaterialTheme.typography.bodySmall.fontSize, - lineHeight = 18.sp - ) - } - - // تلفن - if (detailState.detail.phone.isNotBlank()) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Icon( - imageVector = Icons.Default.Phone, - contentDescription = null, - modifier = Modifier.size(16.dp), - tint = MaterialTheme.colorScheme.primary - ) - Text( - text = detailState.detail.phone, - fontSize = MaterialTheme.typography.bodyMedium.fontSize, - fontWeight = FontWeight.Medium - ) - } - } - } - } - - is PharmacyDetailState.Error -> { - Text( - text = "خطا در دریافت اطلاعات تماس", - fontSize = MaterialTheme.typography.bodySmall.fontSize, - color = MaterialTheme.colorScheme.error - ) - } - - else -> {} - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyResultItem.kt b/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyResultItem.kt new file mode 100644 index 0000000..14db020 --- /dev/null +++ b/app/src/main/java/com/approagency/pharmacy/presentation/components/PharmacyResultItem.kt @@ -0,0 +1,174 @@ +package com.approagency.pharmacy.presentation.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.LocationOn +import androidx.compose.material.icons.filled.Phone +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.approagency.pharmacy.domain.model.PharmacyItem +import com.approagency.pharmacy.presentation.common.CustomBox +import com.approagency.pharmacy.presentation.common.Loading +import com.approagency.pharmacy.presentation.viewModel.PharmacyDetailState +import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel +import com.vada.caller.ui.theme.LocalDime +import com.vada.caller.ui.theme.dime + +@Composable +fun PharmacyResultItem( + pharmacy: PharmacyItem, viewModel: PharmacyViewModel, modifier: Modifier = Modifier +) { + val dime = LocalDime.current + var showDetails by remember { mutableStateOf(false) } + // گرفتن State مخصوص این داروخانه از Map + val detailStates by viewModel.pharmacyDetailStates.collectAsState() + val detailState = detailStates[pharmacy.pharmacyUrl] ?: PharmacyDetailState.Idle + + // Reset detail state when item changes + LaunchedEffect(pharmacy.pharmacyUrl) { + showDetails = false + } + + // Load detail when expanded + LaunchedEffect(showDetails) { + if (showDetails) { + // فقط اگر Idle هست (هنوز لود نشده) درخواست بده + if (detailState is PharmacyDetailState.Idle) { + viewModel.loadPharmacyDetail(pharmacy.pharmacyUrl) + } + } + } + CustomBox( + modifier = modifier.fillMaxWidth(), + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(dime.md), + verticalArrangement = Arrangement.spacedBy(dime.xs) + ) { + // نام برند + Text( + text = pharmacy.brandName, + fontSize = MaterialTheme.typography.labelSmall.fontSize, + color = MaterialTheme.colorScheme.primary + ) + + // نام داروخانه + Text( + text = pharmacy.pharmacyName, + fontWeight = FontWeight.Bold, + fontSize = MaterialTheme.typography.labelLarge.fontSize + ) + + // موقعیت و دکمه اطلاعات تماس + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "${pharmacy.province} - ${pharmacy.city}", + fontSize = MaterialTheme.typography.bodySmall.fontSize, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) + ) + + TextButton( + onClick = { showDetails = !showDetails }) { + Text( + text = if (showDetails) "بستن" else "اطلاعات تماس", + fontSize = MaterialTheme.typography.bodySmall.fontSize + ) + } + } + if (showDetails) { + + when (detailState) { + is PharmacyDetailState.Loading -> { + Row( + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + Loading(size = 24.dp) + } + } + + is PharmacyDetailState.Success -> { + Column( + verticalArrangement = Arrangement.spacedBy(dime.sm) + ) { + HorizontalDivider(modifier = Modifier.padding(vertical = MaterialTheme.dime.xs)) + // آدرس + Row( + verticalAlignment = Alignment.Top, + horizontalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Icon( + imageVector = Icons.Default.LocationOn, + contentDescription = null, + modifier = Modifier.size(16.dp), + tint = MaterialTheme.colorScheme.primary + ) + Text( + text = detailState.detail.address, + fontSize = MaterialTheme.typography.bodySmall.fontSize, + lineHeight = 18.sp + ) + } + + // تلفن + if (detailState.detail.phone.isNotBlank()) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Icon( + imageVector = Icons.Default.Phone, + contentDescription = null, + modifier = Modifier.size(16.dp), + tint = MaterialTheme.colorScheme.primary + ) + Text( + text = detailState.detail.phone, + fontSize = MaterialTheme.typography.bodyMedium.fontSize, + fontWeight = FontWeight.Medium + ) + } + } + } + } + + is PharmacyDetailState.Error -> { + Text( + text = "خطا در دریافت اطلاعات تماس", + fontSize = MaterialTheme.typography.bodySmall.fontSize, + color = MaterialTheme.colorScheme.error + ) + } + + else -> {} + } + } + } + } +} diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/components/drugdetail/DrugDetailComponents.kt b/app/src/main/java/com/approagency/pharmacy/presentation/components/drugdetail/DrugDetailComponents.kt new file mode 100644 index 0000000..1195000 --- /dev/null +++ b/app/src/main/java/com/approagency/pharmacy/presentation/components/drugdetail/DrugDetailComponents.kt @@ -0,0 +1,179 @@ +package com.approagency.pharmacy.presentation.components.drugdetail + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Info +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.vada.caller.ui.theme.LocalDime +import com.vada.caller.ui.theme.dime + +/** + * بلوک‌های مشترکِ ظاهری صفحه‌ی جزئیات دارو. + * این کامپوزبل‌ها در فایل‌های تب (DrugDetailTabs) استفاده می‌شوند. + */ + +/** کارت متنی با عنوانِ سربرگ‌دار و بدنه‌ی توضیحات. */ +@Composable +internal fun InfoSectionCard( + title: String, + content: String, + modifier: Modifier = Modifier +) { + val dime = LocalDime.current + + DetailCard(modifier = modifier) { + SectionHeader(title = title) + Spacer(modifier = Modifier.height(dime.sm)) + Text( + text = content, + style = MaterialTheme.typography.bodyMedium, + lineHeight = 22.sp, + textAlign = TextAlign.Justify, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +/** + * کارت پایه‌ی صفحه‌ی جزئیات — ظاهر یکدست با بقیه‌ی برنامه: + * سطح روشن + قاب نازک هم‌رنگ تم، بدون سایه‌ی سنگین. + */ +@Composable +internal fun DetailCard( + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit +) { + val shape = MaterialTheme.shapes.large + Column( + modifier = modifier + .fillMaxWidth() + .clip(shape) + .background(MaterialTheme.colorScheme.surfaceContainerLowest) + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outlineVariant, + shape = shape + ) + .padding(MaterialTheme.dime.md), + content = content + ) +} + +/** سربرگ بخش با نوار تأکید کوچک کنار عنوان. */ +@Composable +internal fun SectionHeader( + title: String, + modifier: Modifier = Modifier +) { + val dime = LocalDime.current + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Box( + modifier = Modifier + .size(width = 4.dp, height = 18.dp) + .clip(RoundedCornerShape(dime.xxs)) + .background(MaterialTheme.colorScheme.primary) + ) + Text( + text = title, + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary + ) + } +} + +/** حالت «اطلاعاتی ثبت نشده» با آیکن، یکدست در همه‌ی تب‌ها. */ +@Composable +internal fun DetailEmptyState( + text: String, + modifier: Modifier = Modifier +) { + val dime = LocalDime.current + Column( + modifier = modifier + .fillMaxWidth() + .padding(vertical = dime.xxl, horizontal = dime.lg), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Icon( + imageVector = Icons.Default.Info, + contentDescription = null, + modifier = Modifier.size(40.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f) + ) + Text( + text = text, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + } +} + +/** ردیف «برچسب: مقدار» با تایپوگرافی یکدست. */ +@Composable +internal fun LabeledRow( + label: String, + value: String, + modifier: Modifier = Modifier +) { + Row(modifier = modifier) { + Text( + text = "$label: ", + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = value, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.weight(1f) + ) + } +} + +/** برچسب کوچک رنگی (مثل «پرخطر» / «حیاتی»). */ +@Composable +internal fun TagChip( + text: String, + container: Color, + onContainer: Color +) { + Text( + text = text, + style = MaterialTheme.typography.labelSmall, + color = onContainer, + modifier = Modifier + .clip(RoundedCornerShape(MaterialTheme.dime.xs)) + .background(container) + .padding(horizontal = MaterialTheme.dime.sm, vertical = MaterialTheme.dime.xxs) + ) +} diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/components/drugdetail/DrugDetailTabs.kt b/app/src/main/java/com/approagency/pharmacy/presentation/components/drugdetail/DrugDetailTabs.kt new file mode 100644 index 0000000..3eec3d9 --- /dev/null +++ b/app/src/main/java/com/approagency/pharmacy/presentation/components/drugdetail/DrugDetailTabs.kt @@ -0,0 +1,389 @@ +package com.approagency.pharmacy.presentation.components.drugdetail + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Info +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.approagency.pharmacy.domain.model.DrugDetail +import com.approagency.pharmacy.domain.model.GenericInfo +import com.vada.caller.ui.theme.LocalDime + +/** کارت اطلاعات سازنده (برای صفحات برند). */ +@Composable +internal fun ManufacturerInfoCard( + manufacturer: String, + genericInfo: GenericInfo?, + modifier: Modifier = Modifier +) { + val dime = LocalDime.current + val onContainer = MaterialTheme.colorScheme.onSecondaryContainer + + Column( + modifier = modifier + .fillMaxWidth() + .clip(MaterialTheme.shapes.large) + .background(MaterialTheme.colorScheme.secondaryContainer) + .padding(dime.md), + verticalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Icon( + imageVector = Icons.Default.Info, + contentDescription = null, + modifier = Modifier.size(18.dp), + tint = onContainer + ) + Text( + text = "سازنده:", + style = MaterialTheme.typography.labelLarge, + color = onContainer + ) + Text( + text = manufacturer, + style = MaterialTheme.typography.bodyMedium, + color = onContainer + ) + } + + if (genericInfo != null) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(dime.sm) + ) { + Icon( + imageVector = Icons.Default.Info, + contentDescription = null, + modifier = Modifier.size(18.dp), + tint = onContainer + ) + Text( + text = "ماده موثره:", + style = MaterialTheme.typography.labelLarge, + color = onContainer + ) + Text( + text = genericInfo.persianName, + style = MaterialTheme.typography.bodyMedium, + color = onContainer + ) + } + } + } +} + +/** تب «عمومی». */ +@Composable +internal fun GeneralInfoTabContent(drugDetail: DrugDetail) { + val dime = LocalDime.current + + Column(verticalArrangement = Arrangement.spacedBy(dime.md)) { + + if (drugDetail.isGeneric) { + // ========== صفحات ژنریک (Generic) ========== + + // اگر generalInfo وجود دارد (از EtelaatOmomiVaTakhasosi یا EtelaatOmomi) + if (!drugDetail.generalInfo.isNullOrBlank()) { + InfoSectionCard( + title = "اطلاعات عمومی", + content = drugDetail.generalInfo + ) + } + // اگر specializedInfo وجود دارد (از EtelaatTakhasosiContent) + else if (!drugDetail.specializedInfo.isNullOrBlank()) { + InfoSectionCard( + title = "اطلاعات تخصصی", + content = drugDetail.specializedInfo + ) + } + // در غیر این صورت، اطلاعات پراکنده را نمایش بده + else { + // Categories Card + if (drugDetail.drugClass != null || drugDetail.therapeuticClass != null) { + DetailCard { + Column(verticalArrangement = Arrangement.spacedBy(dime.xs)) { + drugDetail.drugClass?.let { + LabeledRow(label = "طبقه بندی مارتیندل", value = it) + } + drugDetail.therapeuticClass?.let { + LabeledRow(label = "طبقه درمانی", value = it) + } + } + } + } + + // Pregnancy Card + if (drugDetail.pregnancyCategory != null || drugDetail.pregnancyDescription != null) { + val onContainer = MaterialTheme.colorScheme.onTertiaryContainer + Column( + modifier = Modifier + .fillMaxWidth() + .clip(MaterialTheme.shapes.large) + .background(MaterialTheme.colorScheme.tertiaryContainer) + .padding(dime.md), + verticalArrangement = Arrangement.spacedBy(dime.xs) + ) { + Text( + text = "مصرف در بارداری", + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + color = onContainer + ) + drugDetail.pregnancyCategory?.let { + Text( + text = "گروه: $it", + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + color = onContainer + ) + } + drugDetail.pregnancyDescription?.let { + Text( + text = it, + style = MaterialTheme.typography.bodySmall, + lineHeight = 18.sp, + color = onContainer.copy(alpha = 0.9f) + ) + } + } + } + + // موارد مصرف + drugDetail.usage?.let { + InfoSectionCard(title = "موارد مصرف", content = it) + } + + // موارد منع مصرف + drugDetail.contraindications?.let { + InfoSectionCard(title = "موارد منع مصرف", content = it) + } + + // عوارض جانبی + drugDetail.sideEffects?.let { + InfoSectionCard(title = "عوارض جانبی", content = it) + } + + // هشدارها + drugDetail.warnings?.let { + InfoSectionCard(title = "هشدارها", content = it) + } + + // توصیه‌های دارویی + drugDetail.recommendations?.let { + InfoSectionCard(title = "توصیه‌های دارویی", content = it) + } + } + + // اگر هیچ اطلاعاتی وجود نداشت + if (drugDetail.drugClass == null && + drugDetail.therapeuticClass == null && + drugDetail.pregnancyCategory == null && + drugDetail.usage == null && + drugDetail.contraindications == null && + drugDetail.sideEffects == null && + drugDetail.warnings == null && + drugDetail.generalInfo.isNullOrBlank() && + drugDetail.specializedInfo.isNullOrBlank() + ) { + DetailEmptyState(text = "اطلاعات عمومی برای این دارو ثبت نشده است") + } + } else { + // ========== صفحات برند (Brand) ========== + // نمایش اطلاعات تخصصی برند که در بخش brandAttrPersDesc است + drugDetail.usage?.let { + InfoSectionCard(title = "موارد مصرف", content = it) + } + drugDetail.contraindications?.let { + InfoSectionCard(title = "موارد منع مصرف", content = it) + } + drugDetail.sideEffects?.let { + InfoSectionCard(title = "عوارض جانبی", content = it) + } + drugDetail.warnings?.let { + InfoSectionCard(title = "هشدارها", content = it) + } + drugDetail.recommendations?.let { + InfoSectionCard(title = "توصیه‌های دارویی", content = it) + } + + if (drugDetail.usage == null && + drugDetail.contraindications == null && + drugDetail.sideEffects == null && + drugDetail.warnings == null + ) { + DetailEmptyState( + text = "اطلاعات عمومی برای این برند ثبت نشده است.\nبرای مشاهده اطلاعات کامل، به صفحه داروی ژنریک مراجعه کنید." + ) + } + } + } +} + +/** تب «تخصصی». */ +@Composable +internal fun SpecializedInfoTabContent(drugDetail: DrugDetail) { + val dime = LocalDime.current + + Column(verticalArrangement = Arrangement.spacedBy(dime.md)) { + + // برای صفحات برند، اطلاعات تخصصی معمولاً در قسمت brandAttrPersDesc است + // که در پارسر ما به صورت usage, contraindications, sideEffects, warnings, recommendations ذخیره شده + + drugDetail.usage?.let { + InfoSectionCard(title = "موارد مصرف", content = it) + } + drugDetail.mechanism?.let { + InfoSectionCard(title = "مکانیسم اثر", content = it) + } + drugDetail.pharmacokinetics?.let { + InfoSectionCard(title = "فارماکوکینتیک", content = it) + } + drugDetail.contraindications?.let { + InfoSectionCard(title = "موارد منع مصرف", content = it) + } + drugDetail.sideEffects?.let { + InfoSectionCard(title = "عوارض جانبی", content = it) + } + drugDetail.interactions?.let { + InfoSectionCard(title = "تداخلات دارویی", content = it) + } + drugDetail.warnings?.let { + InfoSectionCard(title = "هشدارها", content = it) + } + drugDetail.recommendations?.let { + InfoSectionCard(title = "توصیه‌های دارویی", content = it) + } + + // اگر هیچ اطلاعات تخصصی وجود نداشت + if (drugDetail.usage == null && + drugDetail.mechanism == null && + drugDetail.contraindications == null && + drugDetail.sideEffects == null && + drugDetail.warnings == null + ) { + DetailEmptyState( + text = if (drugDetail.isGeneric) + "اطلاعات تخصصی برای این دارو ثبت نشده است" + else + "اطلاعات تخصصی برای این برند ثبت نشده است.\nبرای مشاهده اطلاعات کامل، به صفحه داروی ژنریک مراجعه کنید." + ) + } + } +} + +/** تب «اشکال دارویی». */ +@Composable +internal fun DosageFormsTabContent(drugDetail: DrugDetail) { + val dime = LocalDime.current + val dosageForms = drugDetail.dosageForms + + if (dosageForms.isEmpty()) { + DetailEmptyState( + text = if (drugDetail.isGeneric) + "اشکال دارویی برای این دارو ثبت نشده است" + else + "سایر اشکال دارویی این برند ثبت نشده است" + ) + } else { + Column(verticalArrangement = Arrangement.spacedBy(dime.sm)) { + // اگر صفحه برند است، عنوان متفاوت نشان بده + if (!drugDetail.isGeneric) { + SectionHeader( + title = "سایر محصولات این برند", + modifier = Modifier.padding(bottom = dime.xs) + ) + } + + dosageForms.forEach { form -> + DetailCard { + Text( + text = form.persianName, + style = MaterialTheme.typography.titleSmall + ) + if (form.englishName.isNotBlank()) { + Spacer(modifier = Modifier.height(dime.xxs)) + Text( + text = form.englishName, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + // نشانگرهای خطر + if (form.isHighRisk || form.isVital) { + Spacer(modifier = Modifier.height(dime.sm)) + Row(horizontalArrangement = Arrangement.spacedBy(dime.xs)) { + if (form.isHighRisk) { + TagChip( + text = "پرخطر", + container = MaterialTheme.colorScheme.errorContainer, + onContainer = MaterialTheme.colorScheme.onErrorContainer + ) + } + if (form.isVital) { + TagChip( + text = "حیاتی", + container = MaterialTheme.colorScheme.primaryContainer, + onContainer = MaterialTheme.colorScheme.onPrimaryContainer + ) + } + } + } + } + } + } + } +} + +/** تب «اسامی تجاری». */ +@Composable +internal fun BrandNamesTabContent(drugDetail: DrugDetail) { + val dime = LocalDime.current + + if (drugDetail.isGeneric && drugDetail.brandNames.isEmpty()) { + DetailEmptyState(text = "اسامی تجاری برای این دارو ثبت نشده است") + } else if (drugDetail.isGeneric && drugDetail.brandNames.isNotEmpty()) { + Column(verticalArrangement = Arrangement.spacedBy(dime.sm)) { + drugDetail.brandNames.forEach { brand -> + DetailCard { + Text( + text = brand.persianName, + style = MaterialTheme.typography.titleSmall + ) + brand.manufacturer?.let { + Spacer(modifier = Modifier.height(dime.xs)) + LabeledRow(label = "تولید کننده", value = it) + } + brand.importer?.let { + Spacer(modifier = Modifier.height(dime.xxs)) + LabeledRow(label = "وارد کننده", value = it) + } + } + } + } + } else { + // صفحه برند است - اسامی تجاری برای برند معنی ندارد + DetailEmptyState( + text = "این صفحه مربوط به یک محصول تجاری است. برای مشاهده اسامی تجاری سایر برندها، به صفحه داروی ژنریک مراجعه کنید." + ) + } +} diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/screens/DrugDetailScreen.kt b/app/src/main/java/com/approagency/pharmacy/presentation/screens/DrugDetailScreen.kt index 73fda80..32fe122 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/screens/DrugDetailScreen.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/screens/DrugDetailScreen.kt @@ -1,24 +1,14 @@ package com.approagency.pharmacy.presentation.screens -import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Info import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -38,24 +28,22 @@ import androidx.compose.runtime.remember 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.draw.clip import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController -import com.approagency.pharmacy.domain.model.DrugDetail import com.approagency.pharmacy.presentation.common.ErrorState import com.approagency.pharmacy.presentation.common.Loading +import com.approagency.pharmacy.presentation.components.drugdetail.BrandNamesTabContent +import com.approagency.pharmacy.presentation.components.drugdetail.DosageFormsTabContent +import com.approagency.pharmacy.presentation.components.drugdetail.GeneralInfoTabContent +import com.approagency.pharmacy.presentation.components.drugdetail.ManufacturerInfoCard +import com.approagency.pharmacy.presentation.components.drugdetail.SpecializedInfoTabContent import com.approagency.pharmacy.presentation.viewModel.DrugDetailViewModel import com.approagency.pharmacy.presentation.viewModel.DrugDetailYabState import com.vada.caller.ui.theme.LocalDime -import com.vada.caller.ui.theme.dime import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -140,7 +128,7 @@ fun DrugDetailScreen( val drugDetail = state.drugDetail Column(modifier = Modifier.fillMaxSize()) { - // Manufacturer Info Card (برای صفحات برند) + // کارت سازنده (برای صفحات برند) if (!drugDetail.isGeneric && drugDetail.manufacturer != null) { ManufacturerInfoCard( manufacturer = drugDetail.manufacturer!!, @@ -152,7 +140,6 @@ fun DrugDetailScreen( ) } - // Tab Row TabRow( selectedTabIndex = selectedTab, containerColor = MaterialTheme.colorScheme.surface, @@ -174,7 +161,6 @@ fun DrugDetailScreen( } } - // Tab Content LazyColumn( modifier = Modifier .fillMaxSize() @@ -183,21 +169,10 @@ fun DrugDetailScreen( verticalArrangement = Arrangement.spacedBy(dime.md) ) { when (selectedTab) { - 0 -> { - item { GeneralInfoTabContent(drugDetail) } - } - - 1 -> { - item { SpecializedInfoTabContent(drugDetail) } - } - - 2 -> { - item { DosageFormsTabContent(drugDetail) } - } - - 3 -> { - item { BrandNamesTabContent(drugDetail) } - } + 0 -> item { GeneralInfoTabContent(drugDetail) } + 1 -> item { SpecializedInfoTabContent(drugDetail) } + 2 -> item { DosageFormsTabContent(drugDetail) } + 3 -> item { BrandNamesTabContent(drugDetail) } } } } @@ -219,505 +194,3 @@ fun DrugDetailScreen( } } } - -@Composable -fun ManufacturerInfoCard( - manufacturer: String, - genericInfo: com.approagency.pharmacy.domain.model.GenericInfo?, - modifier: Modifier = Modifier -) { - val dime = LocalDime.current - val onContainer = MaterialTheme.colorScheme.onSecondaryContainer - - Column( - modifier = modifier - .fillMaxWidth() - .clip(MaterialTheme.shapes.large) - .background(MaterialTheme.colorScheme.secondaryContainer) - .padding(dime.md), - verticalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Icon( - imageVector = Icons.Default.Info, - contentDescription = null, - modifier = Modifier.size(18.dp), - tint = onContainer - ) - Text( - text = "سازنده:", - style = MaterialTheme.typography.labelLarge, - color = onContainer - ) - Text( - text = manufacturer, - style = MaterialTheme.typography.bodyMedium, - color = onContainer - ) - } - - if (genericInfo != null) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Icon( - imageVector = Icons.Default.Info, - contentDescription = null, - modifier = Modifier.size(18.dp), - tint = onContainer - ) - Text( - text = "ماده موثره:", - style = MaterialTheme.typography.labelLarge, - color = onContainer - ) - Text( - text = genericInfo.persianName, - style = MaterialTheme.typography.bodyMedium, - color = onContainer - ) - } - } - } -} - -// آپدیت GeneralInfoTabContent برای صفحات Generic -@Composable -fun GeneralInfoTabContent(drugDetail: DrugDetail) { - val dime = LocalDime.current - - Column(verticalArrangement = Arrangement.spacedBy(dime.md)) { - - if (drugDetail.isGeneric) { - // ========== صفحات ژنریک (Generic) ========== - - // اگر generalInfo وجود دارد (از EtelaatOmomiVaTakhasosi یا EtelaatOmomi) - if (!drugDetail.generalInfo.isNullOrBlank()) { - InfoSectionCard( - title = "اطلاعات عمومی", - content = drugDetail.generalInfo - ) - } - // اگر specializedInfo وجود دارد (از EtelaatTakhasosiContent) - else if (!drugDetail.specializedInfo.isNullOrBlank()) { - InfoSectionCard( - title = "اطلاعات تخصصی", - content = drugDetail.specializedInfo - ) - } - // در غیر این صورت، اطلاعات پراکنده را نمایش بده - else { - // Categories Card - if (drugDetail.drugClass != null || drugDetail.therapeuticClass != null) { - DetailCard { - Column(verticalArrangement = Arrangement.spacedBy(dime.xs)) { - drugDetail.drugClass?.let { - LabeledRow(label = "طبقه بندی مارتیندل", value = it) - } - drugDetail.therapeuticClass?.let { - LabeledRow(label = "طبقه درمانی", value = it) - } - } - } - } - - // Pregnancy Card - if (drugDetail.pregnancyCategory != null || drugDetail.pregnancyDescription != null) { - val onContainer = MaterialTheme.colorScheme.onTertiaryContainer - Column( - modifier = Modifier - .fillMaxWidth() - .clip(MaterialTheme.shapes.large) - .background(MaterialTheme.colorScheme.tertiaryContainer) - .padding(dime.md), - verticalArrangement = Arrangement.spacedBy(dime.xs) - ) { - Text( - text = "مصرف در بارداری", - style = MaterialTheme.typography.titleSmall, - fontWeight = FontWeight.Bold, - color = onContainer - ) - drugDetail.pregnancyCategory?.let { - Text( - text = "گروه: $it", - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Medium, - color = onContainer - ) - } - drugDetail.pregnancyDescription?.let { - Text( - text = it, - style = MaterialTheme.typography.bodySmall, - lineHeight = 18.sp, - color = onContainer.copy(alpha = 0.9f) - ) - } - } - } - - // موارد مصرف - drugDetail.usage?.let { - InfoSectionCard(title = "موارد مصرف", content = it) - } - - // موارد منع مصرف - drugDetail.contraindications?.let { - InfoSectionCard(title = "موارد منع مصرف", content = it) - } - - // عوارض جانبی - drugDetail.sideEffects?.let { - InfoSectionCard(title = "عوارض جانبی", content = it) - } - - // هشدارها - drugDetail.warnings?.let { - InfoSectionCard(title = "هشدارها", content = it) - } - - // توصیه‌های دارویی - drugDetail.recommendations?.let { - InfoSectionCard(title = "توصیه‌های دارویی", content = it) - } - } - - // اگر هیچ اطلاعاتی وجود نداشت - if (drugDetail.drugClass == null && - drugDetail.therapeuticClass == null && - drugDetail.pregnancyCategory == null && - drugDetail.usage == null && - drugDetail.contraindications == null && - drugDetail.sideEffects == null && - drugDetail.warnings == null && - drugDetail.generalInfo.isNullOrBlank() && - drugDetail.specializedInfo.isNullOrBlank() - ) { - DetailEmptyState(text = "اطلاعات عمومی برای این دارو ثبت نشده است") - } - } else { - // ========== صفحات برند (Brand) ========== - // نمایش اطلاعات تخصصی برند که در بخش brandAttrPersDesc است - drugDetail.usage?.let { - InfoSectionCard(title = "موارد مصرف", content = it) - } - drugDetail.contraindications?.let { - InfoSectionCard(title = "موارد منع مصرف", content = it) - } - drugDetail.sideEffects?.let { - InfoSectionCard(title = "عوارض جانبی", content = it) - } - drugDetail.warnings?.let { - InfoSectionCard(title = "هشدارها", content = it) - } - drugDetail.recommendations?.let { - InfoSectionCard(title = "توصیه‌های دارویی", content = it) - } - - if (drugDetail.usage == null && - drugDetail.contraindications == null && - drugDetail.sideEffects == null && - drugDetail.warnings == null - ) { - DetailEmptyState( - text = "اطلاعات عمومی برای این برند ثبت نشده است.\nبرای مشاهده اطلاعات کامل، به صفحه داروی ژنریک مراجعه کنید." - ) - } - } - } -} - - -@Composable -fun SpecializedInfoTabContent(drugDetail: DrugDetail) { - val dime = LocalDime.current - - Column(verticalArrangement = Arrangement.spacedBy(dime.md)) { - - // برای صفحات برند، اطلاعات تخصصی معمولاً در قسمت brandAttrPersDesc است - // که در پارسر ما به صورت usage, contraindications, sideEffects, warnings, recommendations ذخیره شده - - drugDetail.usage?.let { - InfoSectionCard(title = "موارد مصرف", content = it) - } - drugDetail.mechanism?.let { - InfoSectionCard(title = "مکانیسم اثر", content = it) - } - drugDetail.pharmacokinetics?.let { - InfoSectionCard(title = "فارماکوکینتیک", content = it) - } - drugDetail.contraindications?.let { - InfoSectionCard(title = "موارد منع مصرف", content = it) - } - drugDetail.sideEffects?.let { - InfoSectionCard(title = "عوارض جانبی", content = it) - } - drugDetail.interactions?.let { - InfoSectionCard(title = "تداخلات دارویی", content = it) - } - drugDetail.warnings?.let { - InfoSectionCard(title = "هشدارها", content = it) - } - drugDetail.recommendations?.let { - InfoSectionCard(title = "توصیه‌های دارویی", content = it) - } - - // اگر هیچ اطلاعات تخصصی وجود نداشت - if (drugDetail.usage == null && - drugDetail.mechanism == null && - drugDetail.contraindications == null && - drugDetail.sideEffects == null && - drugDetail.warnings == null - ) { - DetailEmptyState( - text = if (drugDetail.isGeneric) - "اطلاعات تخصصی برای این دارو ثبت نشده است" - else - "اطلاعات تخصصی برای این برند ثبت نشده است.\nبرای مشاهده اطلاعات کامل، به صفحه داروی ژنریک مراجعه کنید." - ) - } - } -} - -@Composable -fun DosageFormsTabContent(drugDetail: DrugDetail) { - val dime = LocalDime.current - val dosageForms = drugDetail.dosageForms - - if (dosageForms.isEmpty()) { - DetailEmptyState( - text = if (drugDetail.isGeneric) - "اشکال دارویی برای این دارو ثبت نشده است" - else - "سایر اشکال دارویی این برند ثبت نشده است" - ) - } else { - Column(verticalArrangement = Arrangement.spacedBy(dime.sm)) { - // اگر صفحه برند است، عنوان متفاوت نشان بده - if (!drugDetail.isGeneric) { - SectionHeader( - title = "سایر محصولات این برند", - modifier = Modifier.padding(bottom = dime.xs) - ) - } - - dosageForms.forEach { form -> - DetailCard { - Text( - text = form.persianName, - style = MaterialTheme.typography.titleSmall - ) - if (form.englishName.isNotBlank()) { - Spacer(modifier = Modifier.height(dime.xxs)) - Text( - text = form.englishName, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - - // نشانگرهای خطر - if (form.isHighRisk || form.isVital) { - Spacer(modifier = Modifier.height(dime.sm)) - Row(horizontalArrangement = Arrangement.spacedBy(dime.xs)) { - if (form.isHighRisk) { - TagChip( - text = "پرخطر", - container = MaterialTheme.colorScheme.errorContainer, - onContainer = MaterialTheme.colorScheme.onErrorContainer - ) - } - if (form.isVital) { - TagChip( - text = "حیاتی", - container = MaterialTheme.colorScheme.primaryContainer, - onContainer = MaterialTheme.colorScheme.onPrimaryContainer - ) - } - } - } - } - } - } - } -} - -@Composable -fun BrandNamesTabContent(drugDetail: DrugDetail) { - val dime = LocalDime.current - - if (drugDetail.isGeneric && drugDetail.brandNames.isEmpty()) { - DetailEmptyState(text = "اسامی تجاری برای این دارو ثبت نشده است") - } else if (drugDetail.isGeneric && drugDetail.brandNames.isNotEmpty()) { - Column(verticalArrangement = Arrangement.spacedBy(dime.sm)) { - drugDetail.brandNames.forEach { brand -> - DetailCard { - Text( - text = brand.persianName, - style = MaterialTheme.typography.titleSmall - ) - brand.manufacturer?.let { - Spacer(modifier = Modifier.height(dime.xs)) - LabeledRow(label = "تولید کننده", value = it) - } - brand.importer?.let { - Spacer(modifier = Modifier.height(dime.xxs)) - LabeledRow(label = "وارد کننده", value = it) - } - } - } - } - } else { - // صفحه برند است - اسامی تجاری برای برند معنی ندارد - DetailEmptyState( - text = "این صفحه مربوط به یک محصول تجاری است. برای مشاهده اسامی تجاری سایر برندها، به صفحه داروی ژنریک مراجعه کنید." - ) - } -} - -@Composable -fun InfoSectionCard( - title: String, - content: String, - modifier: Modifier = Modifier -) { - val dime = LocalDime.current - - DetailCard(modifier = modifier) { - SectionHeader(title = title) - Spacer(modifier = Modifier.height(dime.sm)) - Text( - text = content, - style = MaterialTheme.typography.bodyMedium, - lineHeight = 22.sp, - textAlign = TextAlign.Justify, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } -} - -/** - * کارت پایه‌ی صفحه‌ی جزئیات — ظاهر یکدست با بقیه‌ی برنامه: - * سطح روشن + قاب نازک هم‌رنگ تم، بدون سایه‌ی سنگین. - */ -@Composable -private fun DetailCard( - modifier: Modifier = Modifier, - content: @Composable ColumnScope.() -> Unit -) { - val shape = MaterialTheme.shapes.large - Column( - modifier = modifier - .fillMaxWidth() - .clip(shape) - .background(MaterialTheme.colorScheme.surfaceContainerLowest) - .border( - width = 1.dp, - color = MaterialTheme.colorScheme.outlineVariant, - shape = shape - ) - .padding(MaterialTheme.dime.md), - content = content - ) -} - -/** سربرگ بخش با نوار تأکید کوچک کنار عنوان. */ -@Composable -private fun SectionHeader( - title: String, - modifier: Modifier = Modifier -) { - val dime = LocalDime.current - Row( - modifier = modifier, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Box( - modifier = Modifier - .size(width = 4.dp, height = 18.dp) - .clip(RoundedCornerShape(dime.xxs)) - .background(MaterialTheme.colorScheme.primary) - ) - Text( - text = title, - style = MaterialTheme.typography.titleSmall, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.primary - ) - } -} - -/** حالت «اطلاعاتی ثبت نشده» با آیکن، یکدست در همه‌ی تب‌ها. */ -@Composable -private fun DetailEmptyState( - text: String, - modifier: Modifier = Modifier -) { - val dime = LocalDime.current - Column( - modifier = modifier - .fillMaxWidth() - .padding(vertical = dime.xxl, horizontal = dime.lg), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(dime.sm) - ) { - Icon( - imageVector = Icons.Default.Info, - contentDescription = null, - modifier = Modifier.size(40.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f) - ) - Text( - text = text, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - textAlign = TextAlign.Center - ) - } -} - -/** ردیف «برچسب: مقدار» با تایپوگرافی یکدست. */ -@Composable -private fun LabeledRow( - label: String, - value: String, - modifier: Modifier = Modifier -) { - Row(modifier = modifier) { - Text( - text = "$label: ", - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurface - ) - Text( - text = value, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.primary, - modifier = Modifier.weight(1f) - ) - } -} - -/** برچسب کوچک رنگی (مثل «پرخطر» / «حیاتی»). */ -@Composable -private fun TagChip( - text: String, - container: Color, - onContainer: Color -) { - Text( - text = text, - style = MaterialTheme.typography.labelSmall, - color = onContainer, - modifier = Modifier - .clip(RoundedCornerShape(MaterialTheme.dime.xs)) - .background(container) - .padding(horizontal = MaterialTheme.dime.sm, vertical = MaterialTheme.dime.xxs) - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/screens/SearchScreen.kt b/app/src/main/java/com/approagency/pharmacy/presentation/screens/SearchScreen.kt index 20471ea..98078ce 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/screens/SearchScreen.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/screens/SearchScreen.kt @@ -37,8 +37,8 @@ import com.approagency.pharmacy.presentation.components.DrugDetailBottomSheet import com.approagency.pharmacy.presentation.components.PharmacyBottomSheet import com.approagency.pharmacy.presentation.viewModel.DrugDetailViewModel import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel -import com.approgency.drug.presentation.viewModel.SearchState -import com.approgency.drug.presentation.viewModel.SearchViewModel +import com.approagency.pharmacy.presentation.viewModel.SearchState +import com.approagency.pharmacy.presentation.viewModel.SearchViewModel import com.vada.caller.ui.theme.LocalDime import com.vada.caller.ui.theme.dime import org.koin.androidx.compose.koinViewModel diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt index dae150e..a744598 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt @@ -1,4 +1,4 @@ -package com.approgency.drug.presentation.viewModel +package com.approagency.pharmacy.presentation.viewModel import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf