Чтение продуктов для главного и дискаунт экранов из апишки. Великая победа над ремоут медиатором.
This commit is contained in:
parent
f52b88e8b6
commit
5c2284ff79
@ -50,7 +50,7 @@ object AppModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideProductRepository(db: AppDatabase) : ProductRepository {
|
||||
return ProductRepository(db.productDao(), db.orderProductDao())
|
||||
return ProductRepository(database = db, db.productDao(), db.orderProductDao())
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.example.shawarma.data.api
|
||||
|
||||
import com.example.shawarma.data.api.models.ProductListResponse
|
||||
import com.example.shawarma.data.api.models.TokenModelRemote
|
||||
import com.example.shawarma.data.api.models.UserModelRemote
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
@ -8,7 +9,10 @@ import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
|
||||
|
||||
interface MyServerService {
|
||||
@ -27,6 +31,15 @@ interface MyServerService {
|
||||
@Body user: UserModelRemote
|
||||
) :UserModelRemote?
|
||||
|
||||
@GET("user/products/{after}")
|
||||
suspend fun getProductsList(@Path("after") after: Int, @Header("Authorization") token: String) : ProductListResponse
|
||||
|
||||
@GET("user/discounts/{after}")
|
||||
suspend fun getDiscountsList(@Path("after") after: Int, @Header("Authorization") token: String) : ProductListResponse
|
||||
|
||||
@GET("user/items/{after}")
|
||||
suspend fun getItemsList(@Path("after") after: Int, @Header("Authorization") token: String) : ProductListResponse
|
||||
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "https://10.0.2.2:80/api/"
|
||||
|
@ -0,0 +1,91 @@
|
||||
package com.example.shawarma.data.api.mediators
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import androidx.room.withTransaction
|
||||
import com.example.shawarma.data.api.MyServerService
|
||||
import com.example.shawarma.data.api.models.ProductListResponse
|
||||
import com.example.shawarma.data.api.models.toProductModel
|
||||
import com.example.shawarma.data.db.AppDatabase
|
||||
import com.example.shawarma.data.models.ProductModel
|
||||
import java.io.IOException
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
class ProductRemoteMediator (
|
||||
private val database: AppDatabase,
|
||||
private val serverService: MyServerService,
|
||||
private val query: String,
|
||||
private val token: String
|
||||
) : RemoteMediator<Int, ProductModel>(){
|
||||
|
||||
private val productDao = database.productDao()
|
||||
|
||||
override suspend fun load(
|
||||
loadType: LoadType,
|
||||
state: PagingState<Int, ProductModel>
|
||||
): MediatorResult {
|
||||
return try {
|
||||
// The network load method takes an optional `after=<user.id>` parameter. For every
|
||||
// page after the first, we pass the last user ID to let it continue from where it
|
||||
// left off. For REFRESH, pass `null` to load the first page.
|
||||
var loadKey = when (loadType) {
|
||||
LoadType.REFRESH -> null
|
||||
// In this example, we never need to prepend, since REFRESH will always load the
|
||||
// first page in the list. Immediately return, reporting end of pagination.
|
||||
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
|
||||
LoadType.APPEND -> {
|
||||
val lastItem = state.lastItemOrNull()
|
||||
?: return MediatorResult.Success(endOfPaginationReached = true)
|
||||
|
||||
// We must explicitly check if the last item is `null` when appending,
|
||||
// since passing `null` to networkService is only valid for initial load.
|
||||
// If lastItem is `null` it means no items were loaded after the initial
|
||||
// REFRESH and there are no more items to load.
|
||||
|
||||
lastItem.id
|
||||
}
|
||||
}
|
||||
|
||||
// Suspending network load via Retrofit. This doesn't need to be wrapped in a
|
||||
// withContext(Dispatcher.IO) { ... } block since Retrofit's Coroutine CallAdapter
|
||||
// dispatches on a worker thread.
|
||||
if (loadKey == null) {
|
||||
loadKey = 0
|
||||
}
|
||||
val response: ProductListResponse = when (query) {
|
||||
"home" -> {
|
||||
serverService.getProductsList(after = loadKey, token = token)
|
||||
}
|
||||
"discounts" -> {
|
||||
serverService.getDiscountsList(after = loadKey, token = token)
|
||||
}
|
||||
"items" -> {
|
||||
serverService.getItemsList(after = loadKey, token = token)
|
||||
}
|
||||
|
||||
else -> {ProductListResponse()}
|
||||
}
|
||||
|
||||
|
||||
database.withTransaction {
|
||||
if (loadType == LoadType.REFRESH) {
|
||||
productDao.deleteByQuery(query)
|
||||
}
|
||||
|
||||
// Insert new users into database, which invalidates the current
|
||||
// PagingData, allowing Paging to present the updates in the DB.
|
||||
val products = mutableListOf<ProductModel>()
|
||||
for (prod in response.products) {
|
||||
products.add(prod.toProductModel())
|
||||
}
|
||||
productDao.insertAll(products)
|
||||
}
|
||||
|
||||
MediatorResult.Success(endOfPaginationReached = response.nextKey == -1)
|
||||
} catch (e: IOException) {
|
||||
MediatorResult.Error(e)
|
||||
}
|
||||
}
|
||||
}
|
@ -8,13 +8,19 @@ data class ProductModelRemote(
|
||||
val id: Int = 0,
|
||||
val title: String = "",
|
||||
val price: Int = 0,
|
||||
val oldPrice: Int? = null
|
||||
val old_price: Int? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ProductListResponse(
|
||||
val products: List<ProductModelRemote> = listOf(),
|
||||
val nextKey: Int? = null
|
||||
)
|
||||
|
||||
fun ProductModelRemote.toProductModel(): ProductModel = ProductModel(
|
||||
id, title, price, oldPrice
|
||||
id, title, price, old_price
|
||||
)
|
||||
|
||||
fun ProductModel.toProductModelRemote(): ProductModelRemote = ProductModelRemote(
|
||||
title = title, price = price, oldPrice = oldPrice
|
||||
title = title, price = price, old_price = oldPrice
|
||||
)
|
||||
|
@ -13,6 +13,12 @@ interface ProductDao {
|
||||
@Insert
|
||||
suspend fun insert(product: ProductModel)
|
||||
|
||||
suspend fun insertAll(products: List<ProductModel>) {
|
||||
for (product in products) {
|
||||
insert(product)
|
||||
}
|
||||
}
|
||||
|
||||
@Update
|
||||
suspend fun update(product: ProductModel)
|
||||
|
||||
@ -39,4 +45,25 @@ interface ProductDao {
|
||||
|
||||
@Query("select * from products")
|
||||
fun getPagedItems(): PagingSource<Int, ProductModel>
|
||||
|
||||
@Query("delete from products where products.product_old_price is null")
|
||||
fun deleteAllProducts()
|
||||
|
||||
@Query("delete from products where products.product_old_price is not null")
|
||||
fun deleteAllDiscountProducts()
|
||||
|
||||
@Query("delete from products")
|
||||
fun deleteAllItems()
|
||||
|
||||
fun deleteByQuery(query: String) {
|
||||
if (query == "home") {
|
||||
deleteAllProducts()
|
||||
}
|
||||
if (query == "discounts") {
|
||||
deleteAllDiscountProducts()
|
||||
}
|
||||
if (query == "items") {
|
||||
deleteAllItems()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
package com.example.shawarma.data.repos
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.example.shawarma.data.api.MyServerService
|
||||
import com.example.shawarma.data.api.mediators.ProductRemoteMediator
|
||||
import com.example.shawarma.data.db.AppDatabase
|
||||
import com.example.shawarma.data.interfaces.dao.OrderProductDao
|
||||
import com.example.shawarma.data.interfaces.dao.ProductDao
|
||||
import com.example.shawarma.data.models.ProductModel
|
||||
@ -10,6 +14,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
|
||||
class ProductRepository @Inject constructor(
|
||||
private val database: AppDatabase,
|
||||
private val productDao: ProductDao,
|
||||
private val orderProductDao: OrderProductDao
|
||||
) {
|
||||
@ -26,20 +31,24 @@ class ProductRepository @Inject constructor(
|
||||
fun getById(id: Int): Flow<ProductModel> {
|
||||
return productDao.getById(id)
|
||||
}
|
||||
fun getAllProductsPaged(): Flow<PagingData<ProductModel>> = Pager(
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
fun getAllProductsPaged(token: String): Flow<PagingData<ProductModel>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = 6,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = productDao::getPaged
|
||||
pagingSourceFactory = productDao::getPaged,
|
||||
remoteMediator = ProductRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "home", token = token)
|
||||
).flow
|
||||
|
||||
fun getAllDiscountsPaged(): Flow<PagingData<ProductModel>> = Pager(
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
fun getAllDiscountsPaged(token: String): Flow<PagingData<ProductModel>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = 6,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = productDao::getPagedDiscounts
|
||||
pagingSourceFactory = productDao::getPagedDiscounts,
|
||||
remoteMediator = ProductRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "discounts", token = token)
|
||||
).flow
|
||||
|
||||
fun getAllItemsPaged(): Flow<PagingData<ProductModel>> = Pager(
|
||||
|
@ -58,9 +58,13 @@ fun DiscountScreen() {
|
||||
|
||||
@Composable
|
||||
fun DiscountList(){
|
||||
val preferencesManager = PreferencesManager(LocalContext.current)
|
||||
val searchToken = preferencesManager.getData("token", "")
|
||||
|
||||
val homeViewModel: HomeViewModel = hiltViewModel<HomeViewModel>()
|
||||
|
||||
val productsListUiState = homeViewModel.discountListUiState.collectAsLazyPagingItems()
|
||||
|
||||
val productsListUiState = homeViewModel.getDiscountList(searchToken).collectAsLazyPagingItems()
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -57,9 +57,13 @@ fun HomeScreen() {
|
||||
|
||||
@Composable
|
||||
fun HomeList(){
|
||||
val preferencesManager = PreferencesManager(LocalContext.current)
|
||||
val searchToken = preferencesManager.getData("token", "")
|
||||
|
||||
val homeViewModel: HomeViewModel = hiltViewModel<HomeViewModel>()
|
||||
|
||||
val productsListUiState = homeViewModel.productListUiState.collectAsLazyPagingItems()
|
||||
|
||||
val productsListUiState = homeViewModel.getProductList(searchToken).collectAsLazyPagingItems()
|
||||
|
||||
|
||||
Box(
|
||||
|
@ -25,9 +25,13 @@ class HomeViewModel @Inject constructor(
|
||||
private val orderProductRepository: OrderProductRepository
|
||||
) : ViewModel() {
|
||||
|
||||
val productListUiState: Flow<PagingData<ProductModel>> = productRepository.getAllProductsPaged()
|
||||
fun getProductList(token:String): Flow<PagingData<ProductModel>> {
|
||||
return productRepository.getAllProductsPaged(token)
|
||||
}
|
||||
|
||||
val discountListUiState: Flow<PagingData<ProductModel>> = productRepository.getAllDiscountsPaged()
|
||||
fun getDiscountList(token: String): Flow<PagingData<ProductModel>> {
|
||||
return productRepository.getAllDiscountsPaged(token)
|
||||
}
|
||||
|
||||
|
||||
fun addProductToCart(productId: Int, userId: String) {
|
||||
|
Loading…
Reference in New Issue
Block a user