diff --git a/app/src/main/java/com/approagency/pharmacy/data/repository/DrugRepositoryImpl.kt b/app/src/main/java/com/approagency/pharmacy/data/repository/DrugRepositoryImpl.kt index 17bbb89..01e4bf6 100644 --- a/app/src/main/java/com/approagency/pharmacy/data/repository/DrugRepositoryImpl.kt +++ b/app/src/main/java/com/approagency/pharmacy/data/repository/DrugRepositoryImpl.kt @@ -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) } } } diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/DrugDetailViewModel.kt b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/DrugDetailViewModel.kt index 6a11176..f58efb4 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/DrugDetailViewModel.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/DrugDetailViewModel.kt @@ -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()) } } } diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/HomeViewModel.kt b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/HomeViewModel.kt index 08953a0..ad0dd3d 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/HomeViewModel.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/HomeViewModel.kt @@ -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 diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/LabViewModel.kt b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/LabViewModel.kt index 669e1e5..cdbc916 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/LabViewModel.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/LabViewModel.kt @@ -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()) } } } diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/PharmacyViewModel.kt b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/PharmacyViewModel.kt index fec554c..be5a012 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/PharmacyViewModel.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/PharmacyViewModel.kt @@ -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()) } } } diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt index a744598..4f1e312 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/viewModel/SearchViewModel.kt @@ -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()) } } } diff --git a/app/src/main/java/com/approagency/pharmacy/utils/ErrorMapper.kt b/app/src/main/java/com/approagency/pharmacy/utils/ErrorMapper.kt new file mode 100644 index 0000000..c45f948 --- /dev/null +++ b/app/src/main/java/com/approagency/pharmacy/utils/ErrorMapper.kt @@ -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 + } +}