feat: error handeling

This commit is contained in:
2026-06-08 20:12:02 +03:30
parent 34ae6a1b54
commit e73269889f
7 changed files with 57 additions and 21 deletions
@@ -67,15 +67,11 @@ class DrugRepositoryImpl(
val searchResult = parser.parseSearchResultsWithPagination(htmlResponse)
if (searchResult.drugs.isNotEmpty()) {
Result.success(searchResult)
} else {
Result.failure(Exception("No drugs found for query: '${params.query}'"))
}
Result.success(searchResult)
} catch (e: IOException) {
Result.failure(Exception("Network error: ${e.message}", e))
Result.failure(e)
} catch (e: Exception) {
Result.failure(Exception("An error occurred: ${e.message}", e))
Result.failure(e)
}
}
}
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.approagency.pharmacy.domain.model.DrugDetail
import com.approagency.pharmacy.domain.usecase.DrugDetailYabUseCase
import com.approagency.pharmacy.utils.toUserMessage
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -22,7 +23,7 @@ class DrugDetailViewModel(
val result = drugDetailUseCase(detailUrl)
_detailState.value = when {
result.isSuccess -> DrugDetailYabState.Success(result.getOrNull()!!)
else -> DrugDetailYabState.Error(result.exceptionOrNull()?.message ?: "خطا در دریافت اطلاعات")
else -> DrugDetailYabState.Error(result.exceptionOrNull().toUserMessage())
}
}
}
@@ -9,6 +9,8 @@ import com.approagency.pharmacy.domain.model.DrugSearchParams
import com.approagency.pharmacy.domain.usecase.GetDarmanUseCase
import com.approagency.pharmacy.domain.usecase.GetDrugDetailUseCase
import com.approagency.pharmacy.domain.usecase.GetDrugSearchUseCase
import com.approagency.pharmacy.utils.ErrorMessages
import com.approagency.pharmacy.utils.toUserMessage
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -49,9 +51,9 @@ class HomeViewModel (
)
}
}catch (e: Exception) {
handleError(e.message)
handleError(e.toUserMessage())
}catch (e: Exception) {
handleError(e.localizedMessage ?: "Unknown error")
handleError(e.toUserMessage())
}
}
}
@@ -73,10 +75,10 @@ class HomeViewModel (
) }
} catch (e: Exception) {
println(e.message)
handleError(e.message)
handleError(e.toUserMessage())
}catch (e: Exception) {
println(e.message)
handleError(e.localizedMessage ?: "Unknown error")
handleError(e.toUserMessage())
}
}
}
@@ -103,9 +105,9 @@ class HomeViewModel (
}
println(result)
} catch (e: Exception) {
handleError(e.message)
handleError(e.toUserMessage())
}catch (e: Exception) {
handleError(e.localizedMessage ?: "Unknown error")
handleError(e.toUserMessage())
}
}
}
@@ -126,7 +128,7 @@ class HomeViewModel (
) , drugDetailState = it.drugDetailState.copy(
isLoading = false
)) }
_event.emit(HomeEvent.ShowError(message ?: "Error occurred"))
_event.emit(HomeEvent.ShowError(message ?: ErrorMessages.GENERIC))
}
// Clear error when consumed
@@ -8,6 +8,7 @@ import com.approagency.pharmacy.domain.model.TestItem
import com.approagency.pharmacy.domain.usecase.GetTestGroupUseCase
import com.approagency.pharmacy.domain.usecase.GetTestItemByGroupId
import com.approagency.pharmacy.domain.usecase.SearchTestsUseCase
import com.approagency.pharmacy.utils.toUserMessage
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -87,7 +88,7 @@ class LabViewModel (
it.copy(
isLoading = false,
searchResults = null,
error = e.message ?: "خطا در جستجو"
error = e.toUserMessage()
)
}
}
@@ -109,7 +110,7 @@ class LabViewModel (
)
}
} catch (e:HttpException){
handleError(e.message)
handleError(e.toUserMessage())
}
}
@@ -132,7 +133,7 @@ class LabViewModel (
)
}
} catch (e:HttpException){
handleError(e.message)
handleError(e.toUserMessage())
}
}
}
@@ -7,6 +7,7 @@ import com.approagency.pharmacy.domain.model.PharmacyDetail
import com.approagency.pharmacy.domain.model.PharmacyItem
import com.approagency.pharmacy.domain.usecase.GetPharmaciesUseCase
import com.approagency.pharmacy.domain.usecase.GetPharmacyDetailUseCase
import com.approagency.pharmacy.utils.toUserMessage
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -61,7 +62,7 @@ class PharmacyViewModel(
}
} catch (e: Exception) {
_pharmacyDetailStates.value = _pharmacyDetailStates.value.toMutableMap().apply {
put(pharmacyUrl, PharmacyDetailState.Error(e.message ?: "خطا در دریافت اطلاعات"))
put(pharmacyUrl, PharmacyDetailState.Error(e.toUserMessage()))
}
}
}
@@ -90,7 +91,7 @@ class PharmacyViewModel(
val result = getPharmaciesUseCase(genericDrugId, brandIrc, provinceId)
_state.value = PharmacyState.Success(result)
} catch (e: Exception) {
_state.value = PharmacyState.Error(e.message ?: "خطا در دریافت اطلاعات")
_state.value = PharmacyState.Error(e.toUserMessage())
}
}
}
@@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.approagency.pharmacy.domain.model.DrugSearchResult
import com.approagency.pharmacy.domain.usecase.SearchDrugsYabUseCase
import com.approagency.pharmacy.utils.toUserMessage
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -77,7 +78,7 @@ class SearchViewModel(
}
else -> {
isLoadingMore = false
SearchState.Error(result.exceptionOrNull()?.message ?: "خطا در جستجو")
SearchState.Error(result.exceptionOrNull().toUserMessage())
}
}
}
@@ -0,0 +1,34 @@
package com.approagency.pharmacy.utils
import retrofit2.HttpException
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
/** پیام‌های خطای فارسیِ امن — بدون افشای منبع داده یا متن خام استثناء. */
object ErrorMessages {
const val NETWORK = "اتصال به اینترنت برقرار نیست. لطفاً اتصال خود را بررسی کرده و دوباره تلاش کنید."
const val TIMEOUT = "زمان پاسخ‌گویی به پایان رسید. لطفاً دوباره تلاش کنید."
const val SERVER = "در حال حاضر امکان دریافت اطلاعات وجود ندارد. لطفاً کمی بعد دوباره تلاش کنید."
const val NOT_FOUND = "موردی یافت نشد."
const val GENERIC = "خطایی رخ داد. لطفاً دوباره تلاش کنید."
}
/**
* تبدیل استثناء به پیام فارسیِ قابلنمایش به کاربر.
* هرگز متن خام استثناء، آدرس سرور یا نام منبع داده را برنمیگرداند.
*/
fun Throwable?.toUserMessage(): String = when (this) {
null -> ErrorMessages.GENERIC
is UnknownHostException -> ErrorMessages.NETWORK
is SocketTimeoutException -> ErrorMessages.TIMEOUT
is HttpException -> ErrorMessages.SERVER
is IOException -> ErrorMessages.NETWORK
else -> when (cause) {
is UnknownHostException -> ErrorMessages.NETWORK
is SocketTimeoutException -> ErrorMessages.TIMEOUT
is HttpException -> ErrorMessages.SERVER
is IOException -> ErrorMessages.NETWORK
else -> ErrorMessages.GENERIC
}
}