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.LabViewModel
|
||||||
import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel
|
import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel
|
||||||
import com.approagency.pharmacy.utils.Config
|
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.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import org.koin.android.ext.koin.androidContext
|
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.layout.Arrangement
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.LocationOn
|
|
||||||
import androidx.compose.material.icons.filled.Phone
|
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
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.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
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.CustomModalBottomSheet
|
||||||
import com.approagency.pharmacy.presentation.common.Loading
|
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.PharmacyState
|
||||||
import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel
|
import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel
|
||||||
import com.approagency.pharmacy.utils.provinces
|
import com.approagency.pharmacy.utils.provinces
|
||||||
import com.vada.caller.ui.theme.LocalDime
|
|
||||||
import com.vada.caller.ui.theme.dime
|
import com.vada.caller.ui.theme.dime
|
||||||
|
|
||||||
@SuppressLint("ConfigurationScreenWidthHeight")
|
@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
|
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.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Info
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -38,24 +28,22 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
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.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
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.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.approagency.pharmacy.domain.model.DrugDetail
|
|
||||||
import com.approagency.pharmacy.presentation.common.ErrorState
|
import com.approagency.pharmacy.presentation.common.ErrorState
|
||||||
import com.approagency.pharmacy.presentation.common.Loading
|
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.DrugDetailViewModel
|
||||||
import com.approagency.pharmacy.presentation.viewModel.DrugDetailYabState
|
import com.approagency.pharmacy.presentation.viewModel.DrugDetailYabState
|
||||||
import com.vada.caller.ui.theme.LocalDime
|
import com.vada.caller.ui.theme.LocalDime
|
||||||
import com.vada.caller.ui.theme.dime
|
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -140,7 +128,7 @@ fun DrugDetailScreen(
|
|||||||
val drugDetail = state.drugDetail
|
val drugDetail = state.drugDetail
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
// Manufacturer Info Card (برای صفحات برند)
|
// کارت سازنده (برای صفحات برند)
|
||||||
if (!drugDetail.isGeneric && drugDetail.manufacturer != null) {
|
if (!drugDetail.isGeneric && drugDetail.manufacturer != null) {
|
||||||
ManufacturerInfoCard(
|
ManufacturerInfoCard(
|
||||||
manufacturer = drugDetail.manufacturer!!,
|
manufacturer = drugDetail.manufacturer!!,
|
||||||
@@ -152,7 +140,6 @@ fun DrugDetailScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tab Row
|
|
||||||
TabRow(
|
TabRow(
|
||||||
selectedTabIndex = selectedTab,
|
selectedTabIndex = selectedTab,
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
@@ -174,7 +161,6 @@ fun DrugDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tab Content
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -183,21 +169,10 @@ fun DrugDetailScreen(
|
|||||||
verticalArrangement = Arrangement.spacedBy(dime.md)
|
verticalArrangement = Arrangement.spacedBy(dime.md)
|
||||||
) {
|
) {
|
||||||
when (selectedTab) {
|
when (selectedTab) {
|
||||||
0 -> {
|
0 -> item { GeneralInfoTabContent(drugDetail) }
|
||||||
item { GeneralInfoTabContent(drugDetail) }
|
1 -> item { SpecializedInfoTabContent(drugDetail) }
|
||||||
}
|
2 -> item { DosageFormsTabContent(drugDetail) }
|
||||||
|
3 -> item { BrandNamesTabContent(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.components.PharmacyBottomSheet
|
||||||
import com.approagency.pharmacy.presentation.viewModel.DrugDetailViewModel
|
import com.approagency.pharmacy.presentation.viewModel.DrugDetailViewModel
|
||||||
import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel
|
import com.approagency.pharmacy.presentation.viewModel.PharmacyViewModel
|
||||||
import com.approgency.drug.presentation.viewModel.SearchState
|
import com.approagency.pharmacy.presentation.viewModel.SearchState
|
||||||
import com.approgency.drug.presentation.viewModel.SearchViewModel
|
import com.approagency.pharmacy.presentation.viewModel.SearchViewModel
|
||||||
import com.vada.caller.ui.theme.LocalDime
|
import com.vada.caller.ui.theme.LocalDime
|
||||||
import com.vada.caller.ui.theme.dime
|
import com.vada.caller.ui.theme.dime
|
||||||
import org.koin.androidx.compose.koinViewModel
|
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.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|||||||
Reference in New Issue
Block a user