feat: clean code

This commit is contained in:
2026-06-12 23:39:17 +03:30
parent 0a4b339481
commit 1ed75fb823
19 changed files with 202 additions and 167 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" /> <bytecodeTargetLevel target="17" />
</component> </component>
</project> </project>
+2 -1
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">
@@ -3,12 +3,18 @@ package com.approagency.pharmacy
import android.app.Application import android.app.Application
import com.approagency.pharmacy.data.local.database.LabDatabase import com.approagency.pharmacy.data.local.database.LabDatabase
import com.approagency.pharmacy.di.appModule import com.approagency.pharmacy.di.appModule
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin import org.koin.core.context.startKoin
class DrugApp : Application() { class DrugApp : Application() {
// اسکوپ سطح‌اپ برای کارهای پس‌زمینه‌ی طول‌عمرِ برنامه (به‌جای GlobalScope).
private val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
startKoin { startKoin {
@@ -17,8 +23,8 @@ class DrugApp : Application(){
printLogger() printLogger()
} }
// Preload database (optional, for faster access) // پیش‌بارگذاری دیتابیس برای دسترسی سریع‌تر
GlobalScope.launch { applicationScope.launch {
LabDatabase.getInstance(this@DrugApp) LabDatabase.getInstance(this@DrugApp)
} }
} }
@@ -20,6 +20,7 @@ import com.approagency.pharmacy.data.local.SessionManager
import com.approagency.pharmacy.domain.repository.AuthRepository import com.approagency.pharmacy.domain.repository.AuthRepository
import com.approagency.pharmacy.navigation.AppNavGraph import com.approagency.pharmacy.navigation.AppNavGraph
import com.approagency.pharmacy.presentation.account.OtpAutoFillBus import com.approagency.pharmacy.presentation.account.OtpAutoFillBus
import com.approagency.pharmacy.presentation.account.OtpAutofillController
import com.approagency.pharmacy.ui.theme.DrugTheme import com.approagency.pharmacy.ui.theme.DrugTheme
import com.google.android.gms.auth.api.phone.SmsRetriever import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.common.api.CommonStatusCodes import com.google.android.gms.common.api.CommonStatusCodes
@@ -27,7 +28,7 @@ import com.google.android.gms.common.api.Status
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity(), OtpAutofillController {
private val session: SessionManager by inject() private val session: SessionManager by inject()
private val authRepository: AuthRepository by inject() private val authRepository: AuthRepository by inject()
@@ -71,7 +72,7 @@ class MainActivity : ComponentActivity() {
// ---------- خودکارپُرکُنِ کد پیامک (SMS User Consent API) ---------- // ---------- خودکارپُرکُنِ کد پیامک (SMS User Consent API) ----------
/** آغاز گوش‌دادن به پیامکِ کد؛ کدِ یافت‌شده از طریق [OtpAutoFillBus] تحویل می‌شود. */ /** آغاز گوش‌دادن به پیامکِ کد؛ کدِ یافت‌شده از طریق [OtpAutoFillBus] تحویل می‌شود. */
fun startOtpAutofill() { override fun startOtpAutofill() {
SmsRetriever.getClient(this).startSmsUserConsent(null) SmsRetriever.getClient(this).startSmsUserConsent(null)
if (otpSmsReceiver != null) return if (otpSmsReceiver != null) return
val receiver = object : BroadcastReceiver() { val receiver = object : BroadcastReceiver() {
@@ -103,7 +104,7 @@ class MainActivity : ComponentActivity() {
) )
} }
fun stopOtpAutofill() { override fun stopOtpAutofill() {
otpSmsReceiver?.let { runCatching { unregisterReceiver(it) } } otpSmsReceiver?.let { runCatching { unregisterReceiver(it) } }
otpSmsReceiver = null otpSmsReceiver = null
} }
@@ -2,7 +2,7 @@ package com.approagency.pharmacy.data.local
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import com.approagency.pharmacy.ui.theme.ThemeMode import com.approagency.pharmacy.domain.model.ThemeMode
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -37,10 +37,8 @@ class DrugRepositoryImpl(
override suspend fun drugDetail(cod: Int): Result<DrugModels> { override suspend fun drugDetail(cod: Int): Result<DrugModels> {
return try { return try {
val response= apiService.getDrugDetail(cod = cod) val response= apiService.getDrugDetail(cod = cod)
println(response.message)
return Result.success(response) return Result.success(response)
}catch (e: Exception){ }catch (e: Exception){
println(e.message)
Result.failure(e) Result.failure(e)
} }
} }
@@ -48,7 +46,6 @@ class DrugRepositoryImpl(
override suspend fun getGorohDaroei(): Result<DarmanModel> { override suspend fun getGorohDaroei(): Result<DarmanModel> {
return try { return try {
val response = apiService.getGorohDaroei() val response = apiService.getGorohDaroei()
println(response)
return Result.success(response) return Result.success(response)
}catch (e: Exception){ }catch (e: Exception){
Result.failure(e) Result.failure(e)
@@ -63,8 +60,6 @@ class DrugRepositoryImpl(
pageNumber = params.pageNumber pageNumber = params.pageNumber
) )
println("HTML Response length: ${htmlResponse.length}")
val searchResult = parser.parseSearchResultsWithPagination(htmlResponse) val searchResult = parser.parseSearchResultsWithPagination(htmlResponse)
Result.success(searchResult) Result.success(searchResult)
@@ -1,4 +1,4 @@
package com.approagency.pharmacy.ui.theme package com.approagency.pharmacy.domain.model
/** حالت نمایش انتخابی کاربر؛ پیش‌فرض پیروی از سیستم است. */ /** حالت نمایش انتخابی کاربر؛ پیش‌فرض پیروی از سیستم است. */
enum class ThemeMode { SYSTEM, LIGHT, DARK } enum class ThemeMode { SYSTEM, LIGHT, DARK }
@@ -0,0 +1,69 @@
package com.approagency.pharmacy.navigation
import androidx.compose.foundation.layout.Column
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.style.TextAlign
import com.approagency.pharmacy.data.local.AccountState
/**
* نوار بالای اپ: دکمهی منو، اطلاعات حساب (موبایل + وضعیت اشتراک) و کنشِ
* ورود/خرید اشتراک.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AccountAppBar(
account: AccountState,
onMenuClick: () -> Unit,
onAccountClick: () -> Unit
) {
TopAppBar(
navigationIcon = {
IconButton(onClick = onMenuClick) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = "منو"
)
}
},
title = {
if (account.isLoggedIn) {
Column {
Text(
text = account.mobile ?: account.displayName.orEmpty(),
style = MaterialTheme.typography.bodyMedium
)
Text(
text = account.subscriptionTitle ?: "بدون اشتراک",
style = MaterialTheme.typography.labelSmall,
color = if (account.isSubscribed)
MaterialTheme.colorScheme.primary
else
MaterialTheme.colorScheme.onSurfaceVariant
)
}
} else {
Text(text = "دارویاب", style = MaterialTheme.typography.titleMedium)
}
},
actions = {
if (!account.isLoggedIn) {
ElevatedButton(onClick = onAccountClick) {
Text("ورود", textAlign = TextAlign.Center)
}
} else if (!account.isSubscribed) {
ElevatedButton(onClick = onAccountClick) {
Text("خرید اشتراک", textAlign = TextAlign.Center)
}
}
}
)
}
@@ -1,22 +1,11 @@
package com.approagency.pharmacy.navigation package com.approagency.pharmacy.navigation
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.DrawerValue import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@@ -27,9 +16,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.approagency.pharmacy.data.local.AccountState
import com.approagency.pharmacy.data.local.SessionManager import com.approagency.pharmacy.data.local.SessionManager
import com.approagency.pharmacy.domain.repository.AuthRepository import com.approagency.pharmacy.domain.repository.AuthRepository
import com.approagency.pharmacy.presentation.account.AccountDrawer import com.approagency.pharmacy.presentation.account.AccountDrawer
@@ -112,53 +99,3 @@ fun MainContainer(
) )
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AccountAppBar(
account: AccountState,
onMenuClick: () -> Unit,
onAccountClick: () -> Unit
) {
TopAppBar(
navigationIcon = {
IconButton(onClick = onMenuClick) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = "منو"
)
}
},
title = {
if (account.isLoggedIn) {
Column {
Text(
text = account.mobile ?: account.displayName.orEmpty(),
style = MaterialTheme.typography.bodyMedium
)
Text(
text = account.subscriptionTitle ?: "بدون اشتراک",
style = MaterialTheme.typography.labelSmall,
color = if (account.isSubscribed)
MaterialTheme.colorScheme.primary
else
MaterialTheme.colorScheme.onSurfaceVariant
)
}
} else {
Text(text = "دارویاب", style = MaterialTheme.typography.titleMedium)
}
},
actions = {
if (!account.isLoggedIn) {
ElevatedButton(onClick = onAccountClick) {
Text("ورود", textAlign = TextAlign.Center)
}
}else if (!account.isSubscribed){
ElevatedButton(onClick = onAccountClick) {
Text("خرید اشتراک", textAlign = TextAlign.Center)
}
}
}
)
}
@@ -43,7 +43,7 @@ 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 com.approagency.pharmacy.data.local.AccountState import com.approagency.pharmacy.data.local.AccountState
import com.approagency.pharmacy.ui.theme.ThemeMode import com.approagency.pharmacy.domain.model.ThemeMode
import com.vada.caller.ui.theme.dime import com.vada.caller.ui.theme.dime
/** /**
@@ -12,9 +12,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
@@ -26,7 +24,6 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
@@ -35,12 +32,9 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
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 com.approagency.pharmacy.MainActivity
import com.approagency.pharmacy.domain.model.SubscriptionProduct
import com.approagency.pharmacy.presentation.common.CustomModalBottomSheet import com.approagency.pharmacy.presentation.common.CustomModalBottomSheet
import com.approagency.pharmacy.presentation.common.OtpTextField import com.approagency.pharmacy.presentation.common.OtpTextField
import com.approagency.pharmacy.presentation.common.PrimaryButton import com.approagency.pharmacy.presentation.common.PrimaryButton
import com.approagency.pharmacy.presentation.common.shimmer
import com.approagency.pharmacy.presentation.viewModel.AccountPhase import com.approagency.pharmacy.presentation.viewModel.AccountPhase
import com.approagency.pharmacy.presentation.viewModel.AccountViewModel import com.approagency.pharmacy.presentation.viewModel.AccountViewModel
import com.vada.caller.ui.theme.dime import com.vada.caller.ui.theme.dime
@@ -71,9 +65,9 @@ fun AccountSheet(
// در مرحله‌ی کد، گوش‌دادن به پیامک را آغاز کن و با خروج متوقفش کن. // در مرحله‌ی کد، گوش‌دادن به پیامک را آغاز کن و با خروج متوقفش کن.
val isOtpStep = ui.phase == AccountPhase.EnterOtp val isOtpStep = ui.phase == AccountPhase.EnterOtp
DisposableEffect(isOtpStep) { DisposableEffect(isOtpStep) {
val mainActivity = activity as? MainActivity val autofill = activity as? OtpAutofillController
if (isOtpStep) mainActivity?.startOtpAutofill() if (isOtpStep) autofill?.startOtpAutofill()
onDispose { mainActivity?.stopOtpAutofill() } onDispose { autofill?.stopOtpAutofill() }
} }
// کدِ خوانده‌شده از پیامک را در فیلد بگذار و به‌صورت خودکار تأیید کن. // کدِ خوانده‌شده از پیامک را در فیلد بگذار و به‌صورت خودکار تأیید کن.
@@ -151,13 +145,13 @@ fun AccountSheet(
ui.productsLoading -> Column( ui.productsLoading -> Column(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.dime.md) verticalArrangement = Arrangement.spacedBy(MaterialTheme.dime.md)
) { ) {
repeat(2) { ProductCardSkeleton() } repeat(2) { SubscriptionProductCardSkeleton() }
} }
else -> Column( else -> Column(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.dime.md) verticalArrangement = Arrangement.spacedBy(MaterialTheme.dime.md)
) { ) {
ui.products.forEach { product -> ui.products.forEach { product ->
ProductCard( SubscriptionProductCard(
product = product, product = product,
isPurchasing = ui.purchasingProductId == product.id, isPurchasing = ui.purchasingProductId == product.id,
onBuy = { activity?.let { viewModel.purchase(it, product) } } onBuy = { activity?.let { viewModel.purchase(it, product) } }
@@ -205,74 +199,3 @@ private fun SheetTitle(text: String) {
Text(text = text, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold) Text(text = text, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
Spacer(Modifier.height(MaterialTheme.dime.xs)) Spacer(Modifier.height(MaterialTheme.dime.xs))
} }
@Composable
private fun ProductCard(
product: SubscriptionProduct,
isPurchasing: Boolean,
onBuy: () -> Unit
) {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(MaterialTheme.dime.lg)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(product.title, style = MaterialTheme.typography.titleMedium)
Text(
"${formatPrice(product.price)} تومان",
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.primary
)
}
if (!product.description.isNullOrBlank()) {
Spacer(Modifier.height(MaterialTheme.dime.xs))
Text(
product.description,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(Modifier.height(MaterialTheme.dime.md))
PrimaryButton(text = "خرید", height = 44, isLoading = isPurchasing, onClick = onBuy)
}
}
}
/** جای‌گیرنده‌ی shimmer برای کارت محصول هنگام بارگذاری. */
@Composable
private fun ProductCardSkeleton() {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(MaterialTheme.dime.lg)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Box(
Modifier
.width(120.dp)
.height(18.dp)
.shimmer()
)
Box(
Modifier
.width(72.dp)
.height(18.dp)
.shimmer()
)
}
Spacer(Modifier.height(MaterialTheme.dime.md))
Box(
Modifier
.fillMaxWidth()
.height(44.dp)
.shimmer(shape = MaterialTheme.shapes.medium)
)
}
}
}
/** قالب‌بندی قیمت با جداکننده‌ی هزارگان. */
private fun formatPrice(price: Long): String =
price.toString().reversed().chunked(3).joinToString(",").reversed()
@@ -0,0 +1,12 @@
package com.approagency.pharmacy.presentation.account
/**
* قراردادِ شروع/توقفِ خودکارپُرکُنِ کدِ پیامک.
*
* اکتیویتی میزبان آن را پیادهسازی میکند؛ شیتِ ورود فقط به این اینترفیس وابسته
* است و از نوعِ مشخصِ اکتیویتی بیخبر میماند.
*/
interface OtpAutofillController {
fun startOtpAutofill()
fun stopOtpAutofill()
}
@@ -0,0 +1,94 @@
package com.approagency.pharmacy.presentation.account
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.width
import androidx.compose.material3.Card
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.unit.dp
import com.approagency.pharmacy.domain.model.SubscriptionProduct
import com.approagency.pharmacy.presentation.common.PrimaryButton
import com.approagency.pharmacy.presentation.common.shimmer
import com.vada.caller.ui.theme.dime
/** کارت یک محصول اشتراک به‌همراه دکمه‌ی خرید. */
@Composable
fun SubscriptionProductCard(
product: SubscriptionProduct,
isPurchasing: Boolean,
onBuy: () -> Unit
) {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(MaterialTheme.dime.lg)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(product.title, style = MaterialTheme.typography.titleMedium)
Text(
"${formatPrice(product.price)} تومان",
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.primary
)
}
if (!product.description.isNullOrBlank()) {
Spacer(Modifier.height(MaterialTheme.dime.xs))
Text(
product.description,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(Modifier.height(MaterialTheme.dime.md))
PrimaryButton(text = "خرید", height = 44, isLoading = isPurchasing, onClick = onBuy)
}
}
}
/** جای‌گیرنده‌ی shimmer برای کارت محصول هنگام بارگذاری. */
@Composable
fun SubscriptionProductCardSkeleton() {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(MaterialTheme.dime.lg)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Box(
Modifier
.width(120.dp)
.height(18.dp)
.shimmer()
)
Box(
Modifier
.width(72.dp)
.height(18.dp)
.shimmer()
)
}
Spacer(Modifier.height(MaterialTheme.dime.md))
Box(
Modifier
.fillMaxWidth()
.height(44.dp)
.shimmer(shape = MaterialTheme.shapes.medium)
)
}
}
}
/** قالب‌بندی قیمت با جداکننده‌ی هزارگان. */
private fun formatPrice(price: Long): String =
price.toString().reversed().chunked(3).joinToString(",").reversed()
@@ -65,7 +65,6 @@ class HomeViewModel (
viewModelScope.launch { viewModelScope.launch {
try { try {
val result = getDrugSearchUseCase.invoke(drugSearchParams) val result = getDrugSearchUseCase.invoke(drugSearchParams)
println(result)
_uiState.update { it.copy( _uiState.update { it.copy(
drugSearchState = it.drugSearchState.copy( drugSearchState = it.drugSearchState.copy(
isLoading = false, isLoading = false,
@@ -74,10 +73,8 @@ class HomeViewModel (
) } ) }
} catch (e: Exception) { } catch (e: Exception) {
println(e.message)
handleError(e.toUserMessage()) handleError(e.toUserMessage())
}catch (e: Exception) { }catch (e: Exception) {
println(e.message)
handleError(e.toUserMessage()) handleError(e.toUserMessage())
} }
} }
@@ -103,7 +100,6 @@ class HomeViewModel (
) )
) )
} }
println(result)
} catch (e: Exception) { } catch (e: Exception) {
handleError(e.toUserMessage()) handleError(e.toUserMessage())
}catch (e: Exception) { }catch (e: Exception) {
@@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import com.approagency.pharmacy.domain.model.ThemeMode
import com.fabirt.podcastapp.ui.theme.Shapes import com.fabirt.podcastapp.ui.theme.Shapes
import com.vada.caller.ui.theme.Dime import com.vada.caller.ui.theme.Dime
import com.vada.caller.ui.theme.LocalDime import com.vada.caller.ui.theme.LocalDime