Skip to content

Commit

Permalink
Pharmacy available medicines now displayed with pagination using Remo…
Browse files Browse the repository at this point in the history
…teMediator.
  • Loading branch information
Nyckoka committed May 23, 2024
1 parent d9e41f8 commit 62c661e
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ interface MedicineDao {
val boxPhotoUrl: String
)

@Upsert
suspend fun upsertPharmacyMedicineList(pharmacyMedicineList: List<PharmacyMedicineEntity>)

@Query("UPDATE medicines SET notificationsActive = :notificationsActive WHERE medicineId = :medicineId")
suspend fun updateMedicineNotificationStatus(
medicineId: Long,
Expand Down Expand Up @@ -82,19 +79,6 @@ interface MedicineDao {
@Query("SELECT * FROM medicines WHERE medicineId = :medicineId")
suspend fun getMedicineById(medicineId: Long): MedicineEntity

@Query(
"""
SELECT medicines.medicineId, medicines.name, medicines.description, medicines.boxPhotoUrl, medicines.notificationsActive, pharmacy_medicine.stock
FROM medicines
INNER JOIN pharmacy_medicine ON medicines.medicineId = pharmacy_medicine.medicineId
WHERE pharmacy_medicine.pharmacyId = :pharmacyId
"""
)
suspend fun getPharmacyMedicineByPharmacyId(pharmacyId: Long): List<PharmacyMedicineFlatEntity>

@Query("DELETE FROM medicines")
suspend fun clearAllMedicines()

@Query("DELETE FROM pharmacy_medicine")
suspend fun clearAllPharmacyMedicine()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import androidx.room.Dao
import androidx.room.Query
import androidx.room.Update
import androidx.room.Upsert
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineEntity
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineFlatEntity

@Dao
interface PharmacyDao {
Expand All @@ -15,13 +17,30 @@ interface PharmacyDao {
@Upsert
suspend fun upsertPharmacy(pharmacy: PharmacyEntity)

@Upsert
suspend fun upsertPharmacyMedicineList(pharmacyMedicineList: List<PharmacyMedicineEntity>)

@Upsert(entity = PharmacyMedicineEntity::class)
suspend fun upsertPharmacyMedicineNoStockList(
pharmacyMedicineNoStockList: List<PharmacyMedicineNoStockEntity>
)

data class PharmacyMedicineNoStockEntity(
val pharmacyId: Long,
val medicineId: Long
)

@Query("UPDATE pharmacies SET userRating = :userRating WHERE pharmacyId = :pharmacyId")
suspend fun updateUserRating(pharmacyId: Long, userRating: Int)

@Update(entity = PharmacyEntity::class)
suspend fun updateGlobalRating(pharmacyEntityGlobalRating: PharmacyEntityGlobalRating)

suspend fun updateGlobalRating(pharmacyId: Long, globalRating: Double, numberOfRatings: Array<Int>) {
suspend fun updateGlobalRating(
pharmacyId: Long,
globalRating: Double,
numberOfRatings: Array<Int>
) {
updateGlobalRating(PharmacyEntityGlobalRating(pharmacyId, globalRating, numberOfRatings))
}

Expand Down Expand Up @@ -49,19 +68,39 @@ interface PharmacyDao {
)
fun pagingSourceByMedicineId(medicineId: Long): PagingSource<Int, PharmacyEntity>

@Query(
"""
SELECT medicines.medicineId, medicines.name, medicines.description, medicines.boxPhotoUrl, medicines.notificationsActive, pharmacy_medicine.stock
FROM medicines
INNER JOIN pharmacy_medicine ON medicines.medicineId = pharmacy_medicine.medicineId
WHERE pharmacy_medicine.pharmacyId = :pharmacyId
"""
)
fun pagingSourcePharmacyMedicineByPharmacyId(pharmacyId: Long): PagingSource<Int, PharmacyMedicineFlatEntity>

@Query("SELECT * FROM pharmacies")
suspend fun getAllPharmacies(): List<PharmacyEntity>

@Query("SELECT * FROM pharmacies WHERE pharmacyId = :id")
suspend fun getPharmacyById(id: Long): PharmacyEntity

/*suspend fun listAvailableMedicines(
pharmacyId: Long,
limit: Long? = null,
offset: Long? = null
): Flow<List<LocalMedicine>>*/

@Query("DELETE FROM pharmacies")
suspend fun clearAllPharmacies()

@Query(
"""
DELETE FROM pharmacies
WHERE pharmacyId IN (
SELECT pharmacyId FROM pharmacy_medicine WHERE medicineId = :medicineId
)
"""
)
suspend fun clearAllPharmaciesByMedicineId(medicineId: Long)

@Query("DELETE FROM pharmacy_medicine")
suspend fun clearAllPharmacyMedicine()

@Query("DELETE FROM pharmacy_medicine WHERE pharmacyId = :pharmacyId")
suspend fun clearPharmacyMedicineByPharmacyId(pharmacyId: Long)
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import pt.ulisboa.ist.pharmacist.domain.medicines.MedicineWithClosestPharmacy
import pt.ulisboa.ist.pharmacist.domain.medicines.MedicineWithNotificationStatus
import pt.ulisboa.ist.pharmacist.repository.local.medicines.MedicineEntity
import pt.ulisboa.ist.pharmacist.repository.local.medicines.MedicineWithClosestPharmacyEntity
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineEntity
import pt.ulisboa.ist.pharmacist.repository.remote.medicines.GetMedicineOutputDto
import pt.ulisboa.ist.pharmacist.repository.remote.pharmacies.MedicineStockDto

fun GetMedicineOutputDto.toMedicineEntity() = MedicineEntity(
medicineId = medicine.medicineId,
Expand All @@ -17,12 +15,6 @@ fun GetMedicineOutputDto.toMedicineEntity() = MedicineEntity(
notificationsActive = notificationsActive
)

fun MedicineStockDto.toPharmacyMedicineEntity(pharmacyId: Long) = PharmacyMedicineEntity(
medicineId = medicine.medicineId,
pharmacyId = pharmacyId,
stock = stock
)

fun MedicineEntity.toMedicine() = Medicine(
medicineId = medicineId,
name = name,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package pt.ulisboa.ist.pharmacist.repository.mappers

import pt.ulisboa.ist.pharmacist.domain.medicines.Medicine
import pt.ulisboa.ist.pharmacist.domain.medicines.MedicineStock
import pt.ulisboa.ist.pharmacist.domain.pharmacies.Location
import pt.ulisboa.ist.pharmacist.domain.pharmacies.Pharmacy
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineFlatEntity
import pt.ulisboa.ist.pharmacist.repository.local.pharmacies.PharmacyEntity
import pt.ulisboa.ist.pharmacist.repository.remote.pharmacies.PharmacyWithUserDataDto

Expand Down Expand Up @@ -29,3 +32,13 @@ fun PharmacyEntity.toPharmacy() = Pharmacy(
userMarkedAsFavorite = userMarkedAsFavorite,
userFlagged = userFlagged
)

fun PharmacyMedicineFlatEntity.toMedicineStock() = MedicineStock(
Medicine(
medicineId = medicineId,
name = name,
description = description,
boxPhotoUrl = boxPhotoUrl
),
stock = stock ?: 0
)
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ class MedicineWithClosestPharmacyRemoteMediator(
return MediatorResult.Error(Exception("Error loading data"))
}

Log.d("MedicineWithClosestPharmacyRemoteMediator", "Result: ${result.data.medicines.size}")
Log.d(
"MedicineWithClosestPharmacyRemoteMediator",
"Result: ${result.data.medicines.size}"
)

pharmacistDb.withTransaction {
if (loadType == LoadType.REFRESH)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package pt.ulisboa.ist.pharmacist.repository.remote.pharmacies

import android.util.Log
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import okio.IOException
import pt.ulisboa.ist.pharmacist.repository.local.PharmacistDatabase
import pt.ulisboa.ist.pharmacist.repository.local.medicines.MedicineDao
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineEntity
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineFlatEntity
import pt.ulisboa.ist.pharmacist.repository.network.connection.isSuccess

@OptIn(ExperimentalPagingApi::class)
class PharmacyMedicinesRemoteMediator(
private val pharmacistDb: PharmacistDatabase,
private val pharmacyApi: PharmacyApi,
private val pharmacyId: Long
) : RemoteMediator<Int, PharmacyMedicineFlatEntity>() {

override suspend fun load(
loadType: LoadType,
state: PagingState<Int, PharmacyMedicineFlatEntity>
): MediatorResult {
val offset = when (loadType) {
LoadType.REFRESH -> STARTING_KEY
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
state.pages.flatten().size
}
}

val limit = state.config.pageSize

Log.d("PharmacyMedicinesRemoteMediator", "LoadType: $loadType")
Log.d(
"PharmacyMedicinesRemoteMediator",
"Item count: ${state.pages.flatten().map { it.medicineId }}"
)
Log.d("PharmacyMedicinesRemoteMediator", "Offset: $offset, Limit: $limit")

return try {
val result = pharmacyApi.listAvailableMedicines(
pharmacyId = pharmacyId,
limit = limit.toLong(),
offset = offset.toLong()
)

if (!result.isSuccess()) {
return MediatorResult.Error(Exception("Error loading data"))
}

Log.d("PharmacyMedicinesRemoteMediator", "Result: ${result.data.medicines.size}")

pharmacistDb.withTransaction {
if (loadType == LoadType.REFRESH)
pharmacistDb.pharmacyDao().clearPharmacyMedicineByPharmacyId(pharmacyId)

pharmacistDb.medicineDao().upsertBaseMedicines(result.data.medicines.map {
MedicineDao.MedicineBaseEntity(
medicineId = it.medicine.medicineId,
name = it.medicine.name,
description = it.medicine.description,
boxPhotoUrl = it.medicine.boxPhotoUrl
)
})
pharmacistDb.pharmacyDao().upsertPharmacyMedicineList(result.data.medicines.map {
PharmacyMedicineEntity(
pharmacyId = pharmacyId,
medicineId = it.medicine.medicineId,
stock = it.stock
)
})
}

Log.d(
"PharmacyMedicinesRemoteMediator",
"Reached end of pagination: ${result.data.medicines.isEmpty() || result.data.medicines.size < limit}"
)

MediatorResult.Success(
endOfPaginationReached =
result.data.medicines.isEmpty() || result.data.medicines.size < limit
)
} catch (e: IOException) {
MediatorResult.Error(e)
} catch (e: Exception) {
MediatorResult.Error(e)
}
}

companion object {
const val STARTING_KEY = 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import androidx.room.withTransaction
import okio.IOException
import pt.ulisboa.ist.pharmacist.domain.pharmacies.Location
import pt.ulisboa.ist.pharmacist.repository.local.PharmacistDatabase
import pt.ulisboa.ist.pharmacist.repository.local.medicines.PharmacyMedicineEntity
import pt.ulisboa.ist.pharmacist.repository.local.pharmacies.PharmacyDao
import pt.ulisboa.ist.pharmacist.repository.local.pharmacies.PharmacyEntity
import pt.ulisboa.ist.pharmacist.repository.mappers.toPharmacyEntity
import pt.ulisboa.ist.pharmacist.repository.network.connection.isSuccess
Expand Down Expand Up @@ -43,17 +43,16 @@ class PharmacyRemoteMediator(

pharmacistDb.withTransaction {
if (loadType == LoadType.REFRESH) {
pharmacistDb.pharmacyDao().clearAllPharmacies()
pharmacistDb.pharmacyDao().clearAllPharmaciesByMedicineId(medicineId)
}
pharmacistDb.pharmacyDao().upsertPharmacies(result.data.pharmacies.map {
it.toPharmacyEntity()
})
pharmacistDb.medicineDao().upsertPharmacyMedicineList(
pharmacistDb.pharmacyDao().upsertPharmacyMedicineNoStockList(
result.data.pharmacies.map {
PharmacyMedicineEntity(
medicineId = medicineId,
PharmacyDao.PharmacyMedicineNoStockEntity( // TODO maybe get stock from API
pharmacyId = it.pharmacy.pharmacyId,
stock = null
medicineId = medicineId
)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.lifecycle.lifecycleScope
import androidx.paging.compose.collectAsLazyPagingItems
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.withCreationCallback
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -54,6 +55,7 @@ class PharmacyActivity : PharmacistActivity() {

Log.d("PharmacyActivity", "Loading pharmacy")
viewModel.loadPharmacy(pharmacyId)
viewModel.triggerUpdateFlow.value = !viewModel.triggerUpdateFlow.value
}

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -72,7 +74,7 @@ class PharmacyActivity : PharmacistActivity() {
PharmacyScreen(
pharmacy = viewModel.pharmacy,
loadingState = viewModel.loadingState,
medicinesList = viewModel.medicinesList,
medicineList = viewModel.medicinePagingFlow.collectAsLazyPagingItems(),
onMedicineClick = { medicineId ->
MedicineActivity.navigate(this, medicineId)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource
import androidx.paging.compose.LazyPagingItems
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.rememberPagerState
import pt.ulisboa.ist.pharmacist.R
Expand All @@ -47,7 +47,7 @@ import pt.ulisboa.ist.pharmacist.ui.screens.shared.components.LoadingSpinner
fun PharmacyScreen(
pharmacy: Pharmacy?,
loadingState: PharmacyViewModel.PharmacyLoadingState,
medicinesList: SnapshotStateMap<Long, MedicineStock>,
medicineList: LazyPagingItems<MedicineStock>,
onMedicineClick: (Long) -> Unit,
onAddMedicineClick: () -> Unit,
onAddStockClick: (Long) -> Unit,
Expand All @@ -57,7 +57,6 @@ fun PharmacyScreen(
onShareClick: () -> Unit,
onRatingChanged: (Int) -> Unit
) {
val medicinesStock = medicinesList.values.toList()
val isLandscape =
LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
val pagerState = rememberPagerState(initialPage = 0)
Expand Down Expand Up @@ -131,11 +130,11 @@ fun PharmacyScreen(
modifier = Modifier.fillMaxWidth(0.35f)
)
PharmacyMedicineList(
medicinesStock,
onAddMedicineClick,
onMedicineClick,
onAddStockClick,
onRemoveStockClick
medicineList = medicineList,
onAddMedicineClick = onAddMedicineClick,
onMedicineClick = onMedicineClick,
onAddStockClick = onAddStockClick,
onRemoveStockClick = onRemoveStockClick
)
}
else
Expand All @@ -159,11 +158,11 @@ fun PharmacyScreen(
modifier = Modifier.fillMaxWidth(0.8f)
)
PharmacyMedicineList(
medicinesStock,
onAddMedicineClick,
onMedicineClick,
onAddStockClick,
onRemoveStockClick
medicineList = medicineList,
onAddMedicineClick = onAddMedicineClick,
onMedicineClick = onMedicineClick,
onAddStockClick = onAddStockClick,
onRemoveStockClick = onRemoveStockClick
)
}
} else
Expand Down
Loading

0 comments on commit 62c661e

Please sign in to comment.