feat: remove drug.approagncy api
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,185 @@
|
||||
package com.approagency.pharmacy.data.local
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.approagency.pharmacy.data.dto.DarmanList
|
||||
import com.approagency.pharmacy.data.dto.DarmanModel
|
||||
import com.approagency.pharmacy.data.dto.DrugDetail
|
||||
import com.approagency.pharmacy.data.dto.DrugListResponse
|
||||
import com.approagency.pharmacy.data.dto.DrugModels
|
||||
import com.approagency.pharmacy.data.dto.GorohDaroei
|
||||
import com.approagency.pharmacy.data.dto.GorohDarmani
|
||||
import com.approagency.pharmacy.data.dto.Meta
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.FileOutputStream
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* منبعِ دادهٔ دارو روی پایگاهدادهٔ همراهِ اپ (`assets/DrugStore.db`).
|
||||
*
|
||||
* تنها منبعِ اطلاعاتِ دارو (جستوجو، جزئیات، گروههای درمانی) است و فقط خواندنی
|
||||
* است. از SQLite خام استفاده میکند (نه Room) تا اعتبارسنجیِ سختگیرانهٔ شِمای
|
||||
* Room روی این دیتابیسِ ثابتِ ازپیشساخته (با کلیدهای خارجی) دردسر نسازد.
|
||||
*/
|
||||
class LocalDrugDataSource(private val context: Context) {
|
||||
|
||||
@Volatile
|
||||
private var db: SQLiteDatabase? = null
|
||||
|
||||
private fun database(): SQLiteDatabase {
|
||||
db?.let { return it }
|
||||
return synchronized(this) {
|
||||
db ?: openReadOnly().also { db = it }
|
||||
}
|
||||
}
|
||||
|
||||
private fun openReadOnly(): SQLiteDatabase {
|
||||
val out = context.getDatabasePath(DB_NAME)
|
||||
if (!out.exists()) {
|
||||
out.parentFile?.mkdirs()
|
||||
context.assets.open(DB_NAME).use { input ->
|
||||
FileOutputStream(out).use { output -> input.copyTo(output) }
|
||||
}
|
||||
}
|
||||
return SQLiteDatabase.openDatabase(out.path, null, SQLiteDatabase.OPEN_READONLY)
|
||||
}
|
||||
|
||||
/** جستوجوی دارو با فیلترهای نام، گروه دارویی و گروه درمانی. */
|
||||
suspend fun searchDrugs(
|
||||
query: String?,
|
||||
drugGroup: Int?,
|
||||
healGroup: Int?,
|
||||
perPage: Int
|
||||
): DrugListResponse = withContext(Dispatchers.IO) {
|
||||
val where = StringBuilder("1=1")
|
||||
val args = mutableListOf<String>()
|
||||
if (!query.isNullOrBlank()) {
|
||||
where.append(" AND (d.nam_fa LIKE ? OR d.nam_en LIKE ?)")
|
||||
args.add("%$query%"); args.add("%$query%")
|
||||
}
|
||||
if (drugGroup != null) { where.append(" AND d.goroh_daroei_cod = ?"); args.add(drugGroup.toString()) }
|
||||
if (healGroup != null) { where.append(" AND d.goroh_darmani_cod = ?"); args.add(healGroup.toString()) }
|
||||
|
||||
val total = database().rawQuery(
|
||||
"SELECT COUNT(*) FROM DrugInfo d WHERE $where", args.toTypedArray()
|
||||
).use { c -> if (c.moveToFirst()) c.getInt(0) else 0 }
|
||||
|
||||
val items = database().rawQuery(
|
||||
"$SELECT_WITH_RELATIONS WHERE $where ORDER BY d.nam_fa LIMIT ?",
|
||||
(args + perPage.toString()).toTypedArray()
|
||||
).use { c -> buildList { while (c.moveToNext()) add(c.toDrugDetail()) } }
|
||||
|
||||
DrugListResponse(
|
||||
success = true,
|
||||
message = null,
|
||||
data = items,
|
||||
meta = Meta(
|
||||
current_page = 1,
|
||||
last_page = if (perPage > 0) ceil(total.toDouble() / perPage).toInt() else 1,
|
||||
per_page = perPage,
|
||||
total = total
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** جزئیات یک دارو بر اساس [cod]. اگر یافت نشود استثناء پرتاب میشود. */
|
||||
suspend fun drugDetail(cod: Int): DrugModels = withContext(Dispatchers.IO) {
|
||||
val detail = database().rawQuery(
|
||||
"$SELECT_WITH_RELATIONS WHERE d.cod = ?", arrayOf(cod.toString())
|
||||
).use { c -> if (c.moveToFirst()) c.toDrugDetail() else null }
|
||||
?: throw NoSuchElementException("دارویی با شناسهٔ $cod در پایگاهدادهٔ محلی یافت نشد.")
|
||||
|
||||
DrugModels(success = true, message = null, data = detail, meta = null)
|
||||
}
|
||||
|
||||
/** فهرست گروههای درمانی (goroh_darmani). */
|
||||
suspend fun darmanGroups(): DarmanModel = withContext(Dispatchers.IO) {
|
||||
val groups = database().rawQuery(
|
||||
"SELECT cod, nam_fa, nam_en FROM goroh_darmani ORDER BY nam_fa", null
|
||||
).use { c ->
|
||||
buildList {
|
||||
while (c.moveToNext()) {
|
||||
add(
|
||||
DarmanList(
|
||||
cod = c.getInt(0),
|
||||
nam_fa = c.getStringOrEmpty(1),
|
||||
nam_en = c.getStringOrEmpty(2)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DarmanModel(success = "true", message = "", data = groups)
|
||||
}
|
||||
|
||||
private fun Cursor.toDrugDetail(): DrugDetail {
|
||||
val daroeiCod = getIntOrNull("goroh_daroei_cod")
|
||||
val darmaniCod = getIntOrNull("goroh_darmani_cod")
|
||||
return DrugDetail(
|
||||
cod = getIntOrNull("cod"),
|
||||
goroh_darmani_detail_cod = getIntOrNull("goroh_darmani_detail_cod"),
|
||||
goroh_daroei_cod = daroeiCod,
|
||||
goroh_farmakologic_cod = getIntOrNull("goroh_farmakologic_cod"),
|
||||
goroh_darmani_cod = darmaniCod,
|
||||
nam_fa = getStringOrNull("nam_fa"),
|
||||
nam_en = getStringOrNull("nam_en"),
|
||||
mavaredmasraf = getStringOrNull("mavaredmasraf"),
|
||||
meghdarmasraf = getStringOrNull("meghdarmasraf"),
|
||||
masrafdarhamelegi = getStringOrNull("masrafdarhamelegi"),
|
||||
masrafdarshirdehi = getStringOrNull("masrafdarshirdehi"),
|
||||
manemasraf = getStringOrNull("manemasraf"),
|
||||
avarez = getStringOrNull("avarez"),
|
||||
tadakhol = getStringOrNull("tadakhol"),
|
||||
mekanismtasir = getStringOrNull("mekanismtasir"),
|
||||
nokte = getStringOrNull("nokte"),
|
||||
hoshdar = getStringOrNull("hoshdar"),
|
||||
sharayetnegahdari = getStringOrNull("sharayetnegahdari"),
|
||||
ashkal_daroei = getStringOrNull("ashkal_daroei"),
|
||||
created_at = null,
|
||||
updated_at = null,
|
||||
goroh_daroei = getStringOrNull("gd_nam")?.let { GorohDaroei(cod = daroeiCod, nam = it, created_at = null, updated_at = null) },
|
||||
goroh_darmani = getStringOrNull("gm_nam_fa")?.let {
|
||||
GorohDarmani(
|
||||
cod = darmaniCod,
|
||||
nam_fa = it,
|
||||
nam_en = getStringOrNull("gm_nam_en"),
|
||||
giyahi_ya_shimiyaei = getStringOrNull("gm_giyahi"),
|
||||
image = getStringOrNull("gm_image"),
|
||||
created_at = null,
|
||||
updated_at = null
|
||||
)
|
||||
},
|
||||
goroh_darmani_detail = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun Cursor.getStringOrNull(name: String): String? {
|
||||
val i = getColumnIndex(name)
|
||||
return if (i >= 0 && !isNull(i)) getString(i) else null
|
||||
}
|
||||
|
||||
private fun Cursor.getStringOrEmpty(index: Int): String =
|
||||
if (!isNull(index)) getString(index) else ""
|
||||
|
||||
private fun Cursor.getIntOrNull(name: String): Int? {
|
||||
val i = getColumnIndex(name)
|
||||
return if (i >= 0 && !isNull(i)) getInt(i) else null
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val DB_NAME = "DrugStore.db"
|
||||
const val SELECT_WITH_RELATIONS = """
|
||||
SELECT d.*,
|
||||
gd.nam AS gd_nam,
|
||||
gm.nam_fa AS gm_nam_fa,
|
||||
gm.nam_en AS gm_nam_en,
|
||||
gm.giyahi_ya_shimiyaei AS gm_giyahi,
|
||||
gm.image AS gm_image
|
||||
FROM DrugInfo d
|
||||
LEFT JOIN goroh_daroei gd ON gd.cod = d.goroh_daroei_cod
|
||||
LEFT JOIN goroh_darmani gm ON gm.cod = d.goroh_darmani_cod
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.approagency.pharmacy.data.remote
|
||||
|
||||
import com.approagency.pharmacy.data.dto.DarmanModel
|
||||
import com.approagency.pharmacy.data.dto.DrugListResponse
|
||||
import com.approagency.pharmacy.data.dto.DrugModels
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface DrugApiService {
|
||||
@GET("drugs/search")
|
||||
suspend fun getDrugs(
|
||||
@Query("q")query: String?,
|
||||
@Query("per_page")perPage:Int? = 20,
|
||||
@Query("with_relations")withRelations: Boolean? =true,
|
||||
@Query("goroh_daroei_cod")drugGroup:Int?,
|
||||
@Query("goroh_darmani_cod")healGroup:Int?,
|
||||
): DrugListResponse
|
||||
|
||||
|
||||
@GET("drugs/{cod}")
|
||||
suspend fun getDrugDetail(
|
||||
@Path("cod") cod: Int
|
||||
): DrugModels
|
||||
|
||||
|
||||
@GET("drugs/goroh-darmani")
|
||||
suspend fun getGorohDaroei(): DarmanModel
|
||||
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package com.approagency.pharmacy.data.repository
|
||||
import com.approagency.pharmacy.data.dto.DarmanModel
|
||||
import com.approagency.pharmacy.data.dto.DrugListResponse
|
||||
import com.approagency.pharmacy.data.dto.DrugModels
|
||||
import com.approagency.pharmacy.data.local.LocalDrugDataSource
|
||||
import com.approagency.pharmacy.data.remote.DarooyabApiService
|
||||
import com.approagency.pharmacy.data.remote.DrugApiService
|
||||
import com.approagency.pharmacy.data.remote.DrugDetailParser
|
||||
import com.approagency.pharmacy.data.remote.DrugHtmlParser
|
||||
import com.approagency.pharmacy.data.remote.PharmacyHtmlParser
|
||||
@@ -20,34 +20,39 @@ import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
|
||||
class DrugRepositoryImpl(
|
||||
private val apiService: DrugApiService,
|
||||
private val darooyabApiService: DarooyabApiService,
|
||||
private val parser: DrugHtmlParser,
|
||||
private val detailParser: DrugDetailParser,
|
||||
private val localDrugDataSource: LocalDrugDataSource,
|
||||
): DrugRepository {
|
||||
// اطلاعات دارو همیشه از پایگاهدادهٔ محلیِ همراهِ اپ (assets/DrugStore.db) خوانده میشود.
|
||||
override suspend fun searchDrug(params: DrugSearchParams): Result<DrugListResponse> {
|
||||
return try {
|
||||
val response = apiService.getDrugs(query = params.query , perPage = params.perPage , withRelations = params.withRelations , healGroup = params.healGroup , drugGroup = params.drugGroup )
|
||||
return Result.success(response)
|
||||
}catch (e: Exception){
|
||||
Result.success(
|
||||
localDrugDataSource.searchDrugs(
|
||||
query = params.query,
|
||||
drugGroup = params.drugGroup,
|
||||
healGroup = params.healGroup,
|
||||
perPage = params.perPage
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun drugDetail(cod: Int): Result<DrugModels> {
|
||||
return try {
|
||||
val response= apiService.getDrugDetail(cod = cod)
|
||||
return Result.success(response)
|
||||
}catch (e: Exception){
|
||||
Result.success(localDrugDataSource.drugDetail(cod))
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getGorohDaroei(): Result<DarmanModel> {
|
||||
return try {
|
||||
val response = apiService.getGorohDaroei()
|
||||
return Result.success(response)
|
||||
}catch (e: Exception){
|
||||
return try {
|
||||
Result.success(localDrugDataSource.darmanGroups())
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package com.approagency.pharmacy.di
|
||||
|
||||
|
||||
import com.approagency.pharmacy.data.billing.StubPurchaseGateway
|
||||
import com.approagency.pharmacy.data.local.LocalDrugDataSource
|
||||
import com.approagency.pharmacy.data.local.SessionManager
|
||||
import com.approagency.pharmacy.data.local.database.LabDatabase
|
||||
import com.approagency.pharmacy.data.remote.ApproApiService
|
||||
import com.approagency.pharmacy.data.remote.AuthInterceptor
|
||||
import com.approagency.pharmacy.data.remote.DarooyabApiService
|
||||
import com.approagency.pharmacy.data.remote.DrugApiService
|
||||
import com.approagency.pharmacy.data.remote.DrugDetailParser
|
||||
import com.approagency.pharmacy.data.remote.DrugHtmlParser
|
||||
import com.approagency.pharmacy.data.repository.AuthRepositoryImpl
|
||||
@@ -47,7 +47,6 @@ import retrofit2.converter.scalars.ScalarsConverterFactory
|
||||
import java.net.CookieManager
|
||||
import java.net.CookiePolicy
|
||||
import java.util.concurrent.TimeUnit
|
||||
val jsonRetrofitQualifier = qualifier("jsonRetrofit")
|
||||
val scalarRetrofitQualifier = qualifier("scalarRetrofit")
|
||||
val authRetrofitQualifier = qualifier("authRetrofit")
|
||||
val appModule= module {
|
||||
@@ -76,19 +75,6 @@ val appModule= module {
|
||||
.build()
|
||||
}
|
||||
|
||||
single<Retrofit>(jsonRetrofitQualifier) { // Add qualifier
|
||||
Retrofit.Builder()
|
||||
.baseUrl(Config.BASE_URL)
|
||||
.client(get<OkHttpClient>())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
}
|
||||
|
||||
single<DrugApiService> {
|
||||
val retrofit: Retrofit = get(jsonRetrofitQualifier) // Get qualified instance
|
||||
retrofit.create(DrugApiService::class.java)
|
||||
}
|
||||
|
||||
// ========== Retrofit for DAROOYAB Website ==========
|
||||
single<Retrofit>(scalarRetrofitQualifier) { // Add qualifier
|
||||
Retrofit.Builder()
|
||||
@@ -135,9 +121,12 @@ val appModule= module {
|
||||
|
||||
factory { DrugHtmlParser() }
|
||||
factory { DrugDetailParser() }
|
||||
// منبع آفلاین دارو (assets/DrugStore.db) برای fallback هنگام خطای شبکه
|
||||
single { LocalDrugDataSource(androidContext()) }
|
||||
|
||||
//repo
|
||||
single<DrugRepository> {
|
||||
DrugRepositoryImpl(get<DrugApiService>() , get<DarooyabApiService>() , get() , get())
|
||||
DrugRepositoryImpl(get<DarooyabApiService>() , get() , get() , get())
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ fun AppNavGraph() {
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = "home"
|
||||
startDestination = "search"
|
||||
) {
|
||||
|
||||
// ───────────────
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
|
||||
@@ -70,7 +71,7 @@ fun BottomBar(navController: NavHostController) {
|
||||
.clickable {
|
||||
if (!selected) {
|
||||
navController.navigate(item.first) {
|
||||
popUpTo("home") {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.approagency.pharmacy.utils
|
||||
|
||||
object Config {
|
||||
const val BASE_URL = "https://drug.approagency.ir/api/"
|
||||
const val Darro_Url = "https://www.darooyab.ir/"
|
||||
|
||||
/** بکاند اشتراک/احراز هویت آپرواجنسی (لاگین، وضعیت، محصولات، خرید). */
|
||||
|
||||
Reference in New Issue
Block a user