feat: clean
This commit is contained in:
@@ -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
|
||||
|
||||
-150
@@ -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 -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
@@ -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 -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
@@ -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)
|
||||
)
|
||||
}
|
||||
+389
@@ -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 = "این صفحه مربوط به یک محصول تجاری است. برای مشاهده اسامی تجاری سایر برندها، به صفحه داروی ژنریک مراجعه کنید."
|
||||
)
|
||||
}
|
||||
}
|
||||
+10
-537
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user