lab 5 work

This commit is contained in:
Володя 2023-12-20 19:45:20 +03:00
parent ef7a12a123
commit 0c949919d8
37 changed files with 1023 additions and 61 deletions

View File

@ -4,6 +4,7 @@ plugins {
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("androidx.navigation.safeargs.kotlin") id("androidx.navigation.safeargs.kotlin")
id("kotlin-kapt") id("kotlin-kapt")
kotlin("plugin.serialization") version "1.4.21"
} }
android { android {
@ -75,6 +76,16 @@ dependencies {
// optional - RxJava3 support // optional - RxJava3 support
implementation("androidx.paging:paging-rxjava3:$paging_version") implementation("androidx.paging:paging-rxjava3:$paging_version")
//retrofit
val retrofitVersion = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.retrofit2:adapter-rxjava3:$retrofitVersion")
implementation("com.squareup.retrofit2:converter-moshi:$retrofitVersion")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// Test // Test
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")

View File

@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application <application
android:name=".PizzaApplication" android:name=".PizzaApplication"
android:allowBackup="true" android:allowBackup="true"
@ -12,6 +16,8 @@
android:roundIcon="@drawable/icon" android:roundIcon="@drawable/icon"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Pizza" android:theme="@style/Theme.Pizza"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31"> tools:targetApi="31">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -2,6 +2,7 @@ package com.example.pizza
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -89,6 +90,10 @@ class Auth : Fragment() {
.actionNavigationAuthToNavigationReg(-1) .actionNavigationAuthToNavigationReg(-1)
Navigation.findNavController(view).navigate(action) Navigation.findNavController(view).navigate(action)
} }
fun openURL() {
val openURL = Intent(Intent.ACTION_VIEW)
openURL.data = Uri.parse("https://ulstu.ru/")
startActivity(openURL)
}
} }

View File

@ -18,6 +18,8 @@ interface BasketDao {
fun getUserAllBasket(uid: Int): Flowable<List<PizzaBasket>> fun getUserAllBasket(uid: Int): Flowable<List<PizzaBasket>>
@Insert @Insert
fun insert(group: Basket): Completable fun insert(group: Basket): Completable
@Insert
fun insertAll(group: List<Basket>): Completable
@Update @Update
fun update(group: Basket): Completable fun update(group: Basket): Completable
@ -26,6 +28,8 @@ interface BasketDao {
fun delete(group: Basket): Completable fun delete(group: Basket): Completable
@Query("delete from basket where basket.user_id = :uid") @Query("delete from basket where basket.user_id = :uid")
fun deleteByUser(uid : Int): Completable fun deleteByUser(uid : Int): Completable
@Query("delete from basket ")
fun deleteAll(): Completable
@Query("delete from basket where basket.user_id = :uid and basket.pizza_id = :pid") @Query("delete from basket where basket.user_id = :uid and basket.pizza_id = :pid")
fun deleteByUserAndPizza(uid : Int, pid:Int): Completable fun deleteByUserAndPizza(uid : Int, pid:Int): Completable
} }

View File

@ -0,0 +1,22 @@
package com.example.pizza.Model.Dto
import com.example.pizza.Model.Basket.Basket
import com.example.pizza.Model.Pizza.Pizza
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable
@Serializable
data class BasketDto(
@SerializedName("user")val user: Int,
@SerializedName("pizza")val pizza: Int,
@SerializedName("count")val countPizza: Int = 1
){
}
fun BasketDto.toBasket(): Basket = Basket(
user, pizza, countPizza)
fun Basket.toBasketDto(): BasketDto = BasketDto(
user, pizza, countPizza
)

View File

@ -0,0 +1,22 @@
package com.example.pizza.Model.Dto
import com.example.pizza.Model.Order.Order
import com.example.pizza.Model.Pizza.Pizza
import kotlinx.serialization.Serializable
import java.util.Date
@Serializable
data class OrderDto(
val uid : Int? = 0,
val date: Long = 0,
val pizza: Int? = 0,
val user: Int? = 0,
val price : Int = 0
)
fun OrderDto.toOrder(): Order = Order(
uid, Date(date), pizza, user, price)
fun Order.toOrderDto(): OrderDto = OrderDto(
uid, date.time, pizza, user, price
)

View File

@ -0,0 +1,45 @@
package com.example.pizza.Model.Dto
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import androidx.annotation.RequiresApi
import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.User.User
import kotlinx.serialization.Serializable
import java.io.ByteArrayOutputStream
import java.util.Base64
@Serializable
data class PizzaDto(
val id : Int?,
val title : String,
val price : Int,
val image : String,
val ingredients : String
){
constructor(
title : String,
price : Int,
image : String,
ingredients : String
) : this(null, title,price, image, ingredients)
}
@RequiresApi(Build.VERSION_CODES.O)
fun PizzaDto.toPizza(): Pizza = Pizza(
id,
title, BitmapFactory.decodeByteArray(Base64.getDecoder().decode(image), 0, Base64.getDecoder().decode(image).size),ingredients,price)
@RequiresApi(Build.VERSION_CODES.O)
fun Pizza.toPizzaDto(): PizzaDto {
val outputStream = ByteArrayOutputStream()
image?.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
val encoded = Base64.getEncoder().encodeToString(outputStream.toByteArray())
return PizzaDto(uid, title,price, encoded, ingredients, )
}

View File

@ -0,0 +1,31 @@
package com.example.pizza.Model.Dto
import com.example.pizza.Model.User.User
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable
@Serializable
data class UserDto(
@SerializedName("id")val id : Int?,
@SerializedName("login")val login : String?,
@SerializedName("email")val email : String?,
@SerializedName("password")val password : String?,
@SerializedName("role")val role : String?
){
constructor(
login: String,
email : String,
password: String,
role : String
) : this(null, login,email,password,role)
}
fun UserDto.toUser(): User = User(
id,
login?:"", email?:"", password?:"", role?:"")
fun User.toUserDto(): UserDto = UserDto(
uid,
login, email, password, role
)

View File

@ -18,6 +18,10 @@ interface OrderDao {
@Insert @Insert
fun insert(group: Order): Completable fun insert(group: Order): Completable
@Delete
fun delete(group: Order): Completable
@Query("DELETE FROM pizzas")
fun deleteAll(): Completable
@Insert @Insert
fun insertMany(group: List<Order>): Completable fun insertMany(group: List<Order>): Completable

View File

@ -16,14 +16,20 @@ import io.reactivex.rxjava3.core.Single
interface PizzaDao { interface PizzaDao {
@Query("select * from pizzas") @Query("select * from pizzas")
fun getAll(): RxPagingSource<Int, Pizza> fun getAll(): RxPagingSource<Int, Pizza>
@Query("select * from pizzas where pizzas.uid = :uid") @Query("select * from pizzas where pizzas.uid = :uid")
fun getById(uid : Int): Single<Pizza> fun getById(uid : Int): Single<Pizza>
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(group: Pizza): Completable fun insert(group: Pizza): Completable
@Insert
fun insertAll(group: List<Pizza>): Completable
@Update @Update
fun update(group: Pizza): Completable fun update(group: Pizza): Completable
@Delete @Delete
fun delete(group: Pizza): Completable fun delete(group: Pizza): Completable
@Query("DELETE FROM pizzas")
fun deleteAll(): Completable
} }

View File

@ -63,7 +63,7 @@ class PizzaAdapter(var context: Context,
holder.price.text = currentPizza.price.toString() holder.price.text = currentPizza.price.toString()
holder.image.setImageBitmap(currentPizza.image) holder.image.setImageBitmap(currentPizza.image)
holder.btn.setOnClickListener { addToBasket(holder, position) } holder.btn.setOnClickListener { addToBasket(holder, position) }
holder.image.setOnClickListener{ onClick(position+1) } holder.image.setOnClickListener{ onClick(pizza.uid!!) }
} }
} }
fun addToBasket(holder: PizzaAdapter.MyViewHolder, position: Int){ fun addToBasket(holder: PizzaAdapter.MyViewHolder, position: Int){

View File

@ -13,6 +13,7 @@ class OfflineBasketRepository(private val basketDao : BasketDao) : BasketReposit
override fun getUserAllBasket(uid: Int): Flowable<List<PizzaBasket>> = basketDao.getUserAllBasket(uid) override fun getUserAllBasket(uid: Int): Flowable<List<PizzaBasket>> = basketDao.getUserAllBasket(uid)
override fun insert(group: Basket): Completable = basketDao.insert(group) override fun insert(group: Basket): Completable = basketDao.insert(group)
fun insertAll(group: List<Basket>): Completable = basketDao.insertAll(group)
override fun update(group: Basket): Completable = basketDao.update(group) override fun update(group: Basket): Completable = basketDao.update(group)
@ -20,5 +21,6 @@ class OfflineBasketRepository(private val basketDao : BasketDao) : BasketReposit
override fun deleteByUser(uid: Int): Completable = basketDao.deleteByUser(uid) override fun deleteByUser(uid: Int): Completable = basketDao.deleteByUser(uid)
fun deleteAll(): Completable = basketDao.deleteAll()
override fun deleteByUserAndPizza(uid: Int, pid: Int): Completable = basketDao.deleteByUserAndPizza(uid,pid) override fun deleteByUserAndPizza(uid: Int, pid: Int): Completable = basketDao.deleteByUserAndPizza(uid,pid)
} }

View File

@ -13,4 +13,6 @@ class OfflineOrderRepository(private val orderDao: OrderDao) : OrderRepository {
override fun insert(group: Order): Completable = orderDao.insert(group) override fun insert(group: Order): Completable = orderDao.insert(group)
override fun insertMany(group: List<Order>): Completable = orderDao.insertMany(group) override fun insertMany(group: List<Order>): Completable = orderDao.insertMany(group)
fun delete(group: Order): Completable = orderDao.delete(group)
fun deleteAll(): Completable = orderDao.deleteAll()
} }

View File

@ -15,4 +15,7 @@ class OfflinePizzaRepository(private val pizzaDao : PizzaDao) : PizzaRepository
override fun update(group: Pizza): Completable = pizzaDao.update(group) override fun update(group: Pizza): Completable = pizzaDao.update(group)
override fun delete(group: Pizza): Completable = pizzaDao.delete(group) override fun delete(group: Pizza): Completable = pizzaDao.delete(group)
override fun deleteAll(): Completable = pizzaDao.deleteAll()
override fun insertAll(pizzas: List<Pizza>): Completable = pizzaDao.insertAll(pizzas)
} }

View File

@ -11,7 +11,7 @@ import io.reactivex.rxjava3.core.Single
class OfflineUserRepository(private val userDao : UserDao) : UserRepository { class OfflineUserRepository(private val userDao : UserDao) : UserRepository {
override fun getById(uid: Int): Single<User> = userDao.getById(uid) override fun getById(uid: Int): Single<User> = userDao.getById(uid)
override fun getAll(): Flowable<List<User>> = userDao.getAll() fun getAll(): Flowable<List<User>> = throw Exception()
override fun getByLoginAndPassword(login: String, pass: String): Single<User> = userDao.getByLoginAndPassword(login,pass) override fun getByLoginAndPassword(login: String, pass: String): Single<User> = userDao.getByLoginAndPassword(login,pass)

View File

@ -11,4 +11,6 @@ interface PizzaRepository {
fun insert(group: Pizza): Completable fun insert(group: Pizza): Completable
fun update(group: Pizza): Completable fun update(group: Pizza): Completable
fun delete(group: Pizza): Completable fun delete(group: Pizza): Completable
fun deleteAll() : Completable
fun insertAll(pizzas: List<Pizza>) : Completable
} }

View File

@ -0,0 +1,150 @@
package com.example.pizza.Model.Repository.Rest.Mediators
import android.annotation.SuppressLint
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.paging.rxjava3.RxRemoteMediator
import com.example.pizza.Model.Dto.toOrder
import com.example.pizza.Model.Dto.toPizza
import com.example.pizza.Model.Order.Order
import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.Repository.OfflineOrderRepository
import com.example.pizza.Model.Repository.OfflinePizzaRepository
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.RemoteKeys.RemoteKeyType
import com.example.pizza.RemoteKeys.RemoteKeys
import com.example.pizza.database.AppDatabase
import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.InvalidObjectException
import java.util.concurrent.atomic.AtomicInteger
@OptIn(ExperimentalPagingApi::class)
class OrderRemoteMediator(
private val service: MyServerService,
private val dbOrderRepository: OfflineOrderRepository,
private val dbPizzaRepository: OfflinePizzaRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase,
private val id : Int
): RxRemoteMediator<Int, Order>() {
@RequiresApi(Build.VERSION_CODES.O)
override fun loadSingle(
loadType: LoadType,
state: PagingState<Int, Order>
): Single<MediatorResult> {
Log.d(this::class.simpleName, state.toString())
return when (loadType){
LoadType.REFRESH -> getRemoteKeyClosestToCurrentPosition(state).subscribeOn(Schedulers.io()).toSingle().map{
Log.d("StudentRemoteMediator", "Refresh" + it.toString())
val page = AtomicInteger(it?.nextKey?.minus(1)?:1)
getMediatorResout(loadType,page,state).blockingGet()
}.onErrorReturn {
data -> Log.d(this::class.simpleName, data.message?:"not message this")
getMediatorResout(loadType, AtomicInteger(1),state).blockingGet() }
LoadType.PREPEND ->
getRemoteKeyForFirstItem(state).subscribeOn(Schedulers.io()).toSingle().map {
Log.d("StudentRemoteMediator", "PREPEND" + it.toString())
if(it?.prevKey != null) {
getMediatorResout(loadType, AtomicInteger(it.prevKey),state).blockingGet()
}
else {
MediatorResult.Success(endOfPaginationReached = it != null)
}
}.onErrorReturn{
data ->Log.d("StudentRemoteMediator", data.message?:"not message this")
MediatorResult.Success(false)}
LoadType.APPEND ->
getRemoteKeyForLastItem(state).subscribeOn(Schedulers.io()).toSingle().map{
Log.d("StudentRemoteMediator", "APPEND" + it.toString())
Log.d(this::class.simpleName, "trying to load more")
if(it?.nextKey != null) {
getMediatorResout(loadType,AtomicInteger(it.nextKey),state).blockingGet()
}
else {
MediatorResult.Success(endOfPaginationReached = it != null)
}
}
.onErrorReturn{
data ->
Log.d(this::class.simpleName, data.message?:"not message this")
MediatorResult.Success(false)}
}
}
@SuppressLint("CheckResult")
@RequiresApi(Build.VERSION_CODES.O)
fun getMediatorResout(loadType: LoadType, page : AtomicInteger, state: PagingState<Int, Order>)
: Single<MediatorResult> {
Log.d(PizzaRemoteMediator::class.simpleName,"Load")
service.getAllPizzas()
.subscribeOn(Schedulers.io())
.map{
database.runInTransaction {
dbPizzaRepository.deleteAll().blockingAwait()
}
dbPizzaRepository.insertAll(it.map { it.toPizza() }).blockingAwait()
}
return service.getUserOrders(id,state.config.pageSize,(page.get()-1)*state.config.pageSize)
.subscribeOn(Schedulers.io())
.map{
database.runInTransaction {
if(loadType == LoadType.REFRESH) {
dbOrderRepository.deleteAll().blockingAwait()
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.ORDER).blockingAwait()
}
dbOrderRepository.insertMany(it.map { it.toOrder() }).blockingAwait()
val prevKey = if (page.get() == 1) null else page.get() - 1
val nextKey = if (it.isEmpty()) null else page.get() + 1
val keys = it.map {
RemoteKeys(
entityId = it.uid!!,
type = RemoteKeyType.ORDER,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys).blockingAwait()
}
MediatorResult.Success(it.isEmpty()) as MediatorResult
}.singleOrError()
.onErrorResumeNext {
e->
Single.just(MediatorResult.Error(e) as MediatorResult)
}
}
private fun getRemoteKeyForLastItem(state: PagingState<Int, Order>): Maybe<RemoteKeys> {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { group ->
dbRemoteKeyRepository.getAllRemoteKeys(group.uid!!, RemoteKeyType.ORDER)
} ?: Maybe.empty()
}
private fun getRemoteKeyForFirstItem(state: PagingState<Int, Order>): Maybe<RemoteKeys> {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { group ->
dbRemoteKeyRepository.getAllRemoteKeys(group.uid!!, RemoteKeyType.ORDER)
}?: Maybe.empty()
}
private fun getRemoteKeyClosestToCurrentPosition( state: PagingState<Int, Order>): Maybe<RemoteKeys> {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { studentUid ->
dbRemoteKeyRepository.getAllRemoteKeys(studentUid, RemoteKeyType.ORDER)
}
}?: Maybe.empty()
}
}

View File

@ -0,0 +1,140 @@
package com.example.pizza.Model.Repository.Rest.Mediators
import android.annotation.SuppressLint
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.paging.rxjava3.RxRemoteMediator
import com.example.pizza.Model.Dto.PizzaDto
import com.example.pizza.Model.Dto.toPizza
import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.Repository.OfflinePizzaRepository
import com.example.pizza.Model.Repository.OfflineUserRepository
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.Model.User.User
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.RemoteKeys.RemoteKeyType
import com.example.pizza.RemoteKeys.RemoteKeys
import com.example.pizza.database.AppDatabase
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.InvalidObjectException
import java.util.concurrent.atomic.AtomicInteger
@OptIn(ExperimentalPagingApi::class)
class PizzaRemoteMediator(
private val service: MyServerService,
private val dbPizzaRepository: OfflinePizzaRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : RxRemoteMediator<Int, Pizza>(){
@RequiresApi(Build.VERSION_CODES.O)
override fun loadSingle(
loadType: LoadType,
state: PagingState<Int, Pizza>
): Single<MediatorResult> {
Log.d(this::class.simpleName, state.toString())
return when (loadType){
LoadType.REFRESH -> getRemoteKeyClosestToCurrentPosition(state).subscribeOn(Schedulers.io()).toSingle().map{
Log.d("StudentRemoteMediator", "Refresh" + it.toString())
val page = AtomicInteger(it?.nextKey?.minus(1)?:1)
getMediatorResout(loadType,page,state).blockingGet()
}.onErrorReturn {
data -> Log.d(this::class.simpleName, data.message?:"not message this")
getMediatorResout(loadType, AtomicInteger(1),state).blockingGet() }
LoadType.PREPEND ->
getRemoteKeyForFirstItem(state).subscribeOn(Schedulers.io()).toSingle().map {
Log.d("StudentRemoteMediator", "PREPEND" + it.toString())
if(it?.prevKey != null) {
getMediatorResout(loadType, AtomicInteger(it.prevKey),state).blockingGet()
}
else {
MediatorResult.Success(endOfPaginationReached = it != null)
}
}.onErrorReturn{
data ->Log.d("StudentRemoteMediator", data.message?:"not message this")
MediatorResult.Success(false)}
LoadType.APPEND ->
getRemoteKeyForLastItem(state).subscribeOn(Schedulers.io()).toSingle().map{
Log.d("StudentRemoteMediator", "APPEND" + it.toString())
Log.d(this::class.simpleName, "trying to load more")
if(it?.nextKey != null) {
getMediatorResout(loadType,AtomicInteger(it.nextKey),state).blockingGet()
}
else {
MediatorResult.Success(endOfPaginationReached = it != null)
}
}
.onErrorReturn{
data ->
Log.d(this::class.simpleName, data.message?:"not message this")
MediatorResult.Success(false)}
}
}
@SuppressLint("CheckResult")
@RequiresApi(Build.VERSION_CODES.O)
fun getMediatorResout(loadType: LoadType, page : AtomicInteger, state: PagingState<Int, Pizza>)
: Single<MediatorResult> {
Log.d(PizzaRemoteMediator::class.simpleName,"Load")
return service.getPizzas(state.config.pageSize,(page.get()-1)*state.config.pageSize)
.subscribeOn(Schedulers.io())
.map{
database.runInTransaction {
if(loadType == LoadType.REFRESH) {
dbPizzaRepository.deleteAll().blockingAwait()
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.PIZZA).blockingAwait()
}
dbPizzaRepository.insertAll(it.map { it.toPizza() }).blockingAwait()
val prevKey = if (page.get() == 1) null else page.get() - 1
val nextKey = if (it.isEmpty()) null else page.get() + 1
val keys = it.map {
RemoteKeys(
entityId = it.id!!,
type = RemoteKeyType.PIZZA,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys).blockingAwait()
}
MediatorResult.Success(it.isEmpty()) as MediatorResult
}.singleOrError()
.onErrorResumeNext {
e->
Single.just(MediatorResult.Error(e) as MediatorResult)
}
}
private fun getRemoteKeyForLastItem(state: PagingState<Int, Pizza>): Maybe<RemoteKeys> {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { group ->
dbRemoteKeyRepository.getAllRemoteKeys(group.uid!!, RemoteKeyType.PIZZA)
} ?: Maybe.empty()
}
private fun getRemoteKeyForFirstItem(state: PagingState<Int, Pizza>): Maybe<RemoteKeys> {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { group ->
dbRemoteKeyRepository.getAllRemoteKeys(group.uid!!, RemoteKeyType.PIZZA)
}?: Maybe.empty()
}
private fun getRemoteKeyClosestToCurrentPosition( state: PagingState<Int, Pizza>): Maybe<RemoteKeys> {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { studentUid ->
dbRemoteKeyRepository.getAllRemoteKeys(studentUid, RemoteKeyType.PIZZA)
}
}?: Maybe.empty()
}
}

View File

@ -0,0 +1,80 @@
package com.example.pizza.Model.Repository.Rest
import android.annotation.SuppressLint
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.paging.rxjava3.RxPagingSource
import com.example.pizza.Model.Basket.Basket
import com.example.pizza.Model.Basket.PizzaBasket
import com.example.pizza.Model.Dto.BasketDto
import com.example.pizza.Model.Dto.toBasket
import com.example.pizza.Model.Dto.toBasketDto
import com.example.pizza.Model.Dto.toPizza
import com.example.pizza.Model.Dto.toUserDto
import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.Repository.BasketRepository
import com.example.pizza.Model.Repository.OfflineBasketRepository
import com.example.pizza.Model.Repository.OfflinePizzaRepository
import com.example.pizza.Model.Repository.OfflineUserRepository
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.database.AppDatabase
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.internal.wait
class RestBasketRepository(private val service: MyServerService,
private val dbBasketRepository: OfflineBasketRepository,
private val dbPizzaRepository: OfflinePizzaRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : BasketRepository {
var AllBaskets : MutableLiveData<RxPagingSource<Int, PizzaBasket>?> = MutableLiveData()
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("CheckResult")
override fun getUserBasket(uid: Int): RxPagingSource<Int, PizzaBasket> {
insertAll(uid)
return AllBaskets.value!!
}
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("CheckResult")
fun insertAll(uid: Int){
Log.d("RestBasketRepository", "Insert All")
Observable.zip(service.getUserBaskets(uid),service.getAllPizzas()){
baskets,pizzas ->
Log.d("RestBasketRepository", "Insert All")
val bks = baskets.map { it.toBasket() }
val ps = pizzas.map { it.toPizza() }
database.runInTransaction{
dbBasketRepository.deleteAll().blockingAwait()
dbPizzaRepository.deleteAll().blockingAwait()
dbBasketRepository.insertAll(bks).blockingAwait()
dbPizzaRepository.insertAll(ps).blockingAwait()
}
}.map { dbBasketRepository.getUserBasket(uid) }.subscribe { data -> AllBaskets.postValue(data)}
}
@SuppressLint("CheckResult")
override fun insert(group: Basket): Completable = Completable.fromObservable(service.createBasket(group.toBasketDto()))
override fun getUserAllBasket(uid: Int): Flowable<List<PizzaBasket>> {
return dbBasketRepository.getUserAllBasket(uid)
}
override fun update(group: Basket): Completable = throw Exception()
override fun delete(group: Basket): Completable {
throw Exception()
}
override fun deleteByUser(uid: Int): Completable = Completable.fromObservable(service.deleteUserBaskets(uid))
override fun deleteByUserAndPizza(uid: Int, pid: Int): Completable = Completable.fromObservable(service.deleteBasket(
BasketDto(uid,pid,1)
))
}

View File

@ -0,0 +1,54 @@
package com.example.pizza.Model.Repository.Rest
import android.database.Observable
import androidx.paging.rxjava3.RxPagingSource
import androidx.room.Index
import com.example.pizza.Model.Dto.OrderDto
import com.example.pizza.Model.Dto.toOrderDto
import com.example.pizza.Model.Order.Order
import com.example.pizza.Model.Order.PizzaOrder
import com.example.pizza.Model.Repository.OfflineOrderRepository
import com.example.pizza.Model.Repository.OfflinePizzaRepository
import com.example.pizza.Model.Repository.OrderRepository
import com.example.pizza.Model.Repository.Rest.Mediators.OrderRemoteMediator
import com.example.pizza.Model.Repository.Rest.Mediators.PizzaRemoteMediator
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.database.AppDatabase
import io.reactivex.rxjava3.core.Completable
class RestOrderRepository(private val service: MyServerService,
private val dbOrderRepository: OfflineOrderRepository,
private val dbPizzaRepository: OfflinePizzaRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : OrderRepository {
var mediator: OrderRemoteMediator? = null
override fun getUserHistory(uid: Int): RxPagingSource<Int, PizzaOrder> {
if (mediator==null){
mediator = OrderRemoteMediator(
service,
dbOrderRepository,
dbPizzaRepository,
dbRemoteKeyRepository,
database,
uid
)
}
return dbOrderRepository.getUserHistory(uid)
}
override fun insert(group: Order): Completable = Completable.fromObservable(service.createOrder(group.toOrderDto()))
override fun insertMany(orders: List<Order>): Completable
{
var list : MutableList <OrderDto> = mutableListOf<OrderDto>()
for (order in orders){
list.add(order.toOrderDto())
}
return Completable.fromObservable(service.createOrders(list))
}
}

View File

@ -0,0 +1,62 @@
package com.example.pizza.Model.Repository.Rest
import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.paging.rxjava3.RxPagingSource
import com.example.pizza.Model.Dto.toPizza
import com.example.pizza.Model.Dto.toPizzaDto
import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.Repository.OfflinePizzaRepository
import com.example.pizza.Model.Repository.PizzaRepository
import com.example.pizza.Model.Repository.Rest.Mediators.PizzaRemoteMediator
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.database.AppDatabase
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import java.net.ConnectException
import java.net.SocketTimeoutException
class RestPizzaRepository(
private val service: MyServerService,
private val dbPizzaRepository: OfflinePizzaRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : PizzaRepository{
var mediator: PizzaRemoteMediator? = null
override fun getAll(): RxPagingSource<Int, Pizza> {
if (mediator==null){
mediator = PizzaRemoteMediator(
service,
dbPizzaRepository,
dbRemoteKeyRepository,
database,
)
}
return dbPizzaRepository.getAll()
}
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("CheckResult")
override fun getById(uid: Int): Single<Pizza> {
return service.getPizza(uid).subscribeOn(Schedulers.io()).map { it.toPizza() }
}
@RequiresApi(Build.VERSION_CODES.O)
override fun insert(group: Pizza): Completable = Completable.fromObservable(
service.createPizza(group.toPizzaDto()))
@RequiresApi(Build.VERSION_CODES.O)
override fun update(group: Pizza): Completable = Completable.fromObservable(
service.updatePizza(group.uid!!,group.toPizzaDto()))
override fun delete(group: Pizza): Completable = throw Exception()
override fun deleteAll(): Completable = throw Exception()
override fun insertAll(pizzas: List<Pizza>): Completable = throw Exception()
}

View File

@ -0,0 +1,41 @@
package com.example.pizza.Model.Repository.Rest
import android.annotation.SuppressLint
import android.util.Log
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.pizza.Model.Dto.toUser
import com.example.pizza.Model.Dto.toUserDto
import com.example.pizza.Model.Repository.OfflineUserRepository
import com.example.pizza.Model.Repository.UserRepository
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.Model.User.User
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.database.AppDatabase
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Single
class RestUserRepository (
private val service: MyServerService,
private val dbUserRepository: OfflineUserRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : UserRepository {
@SuppressLint("CheckResult")
override fun getById(uid: Int): Single<User> = service.getUser(uid).map { it.toUser() }
override fun getByLoginAndPassword(login: String, pass: String): Single<User> {
return service.getUserLP(login, pass).map {
Log.d(RestUserRepository::class.simpleName ,it.toString())
it.toUser() }
}
override fun insert(group: User): Completable = Completable.fromObservable(service.createUser(group.toUserDto()))
override fun update(group: User): Completable = Completable.fromObservable(service.updateUser(group.uid!!,group.toUserDto()))
override fun delete(group: User): Completable = Completable.fromObservable(service.updateUser(group.uid!!,group.toUserDto()))
}

View File

@ -12,8 +12,6 @@ import io.reactivex.rxjava3.core.Single
interface UserRepository { interface UserRepository {
fun getById(uid : Int): Single<User> fun getById(uid : Int): Single<User>
fun getAll(): Flowable<List<User>>
fun getByLoginAndPassword(login : String, pass : String): Single<User> fun getByLoginAndPassword(login : String, pass : String): Single<User>
fun insert(group: User): Completable fun insert(group: User): Completable

View File

@ -0,0 +1,149 @@
package com.example.pizza.Model.Rest
import com.example.pizza.Model.Dto.BasketDto
import com.example.pizza.Model.Dto.OrderDto
import com.example.pizza.Model.Dto.PizzaDto
import com.example.pizza.Model.Dto.UserDto
import com.google.gson.GsonBuilder
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.Field
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
interface MyServerService {
@GET("pizzas")
fun getPizzas(
@Query("limit") limit: Int,
@Query("offset") offset: Int,
): Flowable<List<PizzaDto>>
@GET("allpizzas")
fun getAllPizzas(
): Observable<List<PizzaDto>>
@GET("baskets/{id}")
fun getUserBaskets(
@Path("id") id: Int,
): Observable<List<BasketDto>>
@GET("pizza/{id}")
fun getPizza(
@Path("id") id: Int,
): Single<PizzaDto>
@GET("baskets")
fun getAllBaskets(
): Observable<List<BasketDto>>
@GET("orders/{id}")
fun getUserOrders(
@Path("id") id: Int,
@Query("page") page: Int,
@Query("size") limit: Int,
): Observable<List<OrderDto>>
@GET("orders")
fun getAllOrders(
): Observable<List<OrderDto>>
@GET("users")
fun getAllUsers(
): Observable<UserDto>
@GET("user/{id}")
fun getUser(
@Path("id") id: Int,
): Single<UserDto>
@GET("user")
fun getUserLP(
@Query("login") login : String ,
@Query("password") password : String
): Single<UserDto>
@POST("user")
fun createUser(
@Body user: UserDto,
): Observable<UserDto>
@POST("pizza")
fun createPizza(
@Body pizza: PizzaDto,
): Observable<PizzaDto>
@POST("basket")
fun createBasket(
@Body basket: BasketDto,
): Observable<BasketDto>
@POST("order")
fun createOrder(
@Body order: OrderDto,
): Observable<OrderDto>
@POST("orders")
fun createOrders(
@Body order: List<OrderDto>,
): Observable<OrderDto>
@PUT("user/{id}")
fun updateUser(
@Path("id") id: Int,
@Body user: UserDto,
): Observable<UserDto>
@PUT("pizza/{id}")
fun updatePizza(
@Path("id") id: Int,
@Body user: PizzaDto,
): Observable<PizzaDto>
@DELETE("baskets/{id}")
fun deleteUserBaskets(
@Path("id") id: Int,
): Observable<BasketDto>
@DELETE("basket")
fun deleteBasket(
@Body user: BasketDto,
): Observable<BasketDto>
companion object {
private const val BASE_URL = "http://192.168.42.168:8080/api/"
@Volatile
private var INSTANCE: MyServerService? = null
fun getInstance(): MyServerService {
return INSTANCE ?: synchronized(this) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
val gsonBuilder = GsonBuilder()
gsonBuilder.setLenient()
val gson = gsonBuilder.create()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
//.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
//.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
.create(MyServerService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,15 @@
package com.example.pizza.RemoteKeys
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Maybe
class OfflineRemoteKeyRepository(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository {
override fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
remoteKeysDao.getRemoteKeys(id, type)
override fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
remoteKeysDao.insertAll(remoteKeys)
override fun deleteRemoteKey(type: RemoteKeyType) =
remoteKeysDao.clearRemoteKeys(type)
}

View File

@ -0,0 +1,10 @@
package com.example.pizza.RemoteKeys
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Maybe
interface RemoteKeyRepository {
fun getAllRemoteKeys(id: Int, type: RemoteKeyType): Maybe<RemoteKeys>
fun createRemoteKeys(remoteKeys: List<RemoteKeys>) : Completable
fun deleteRemoteKey(type: RemoteKeyType) : Completable
}

View File

@ -0,0 +1,32 @@
package com.example.pizza.RemoteKeys
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import com.example.pizza.Model.User.User
import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.Basket.Basket
import com.example.pizza.Model.Order.Order
@Entity(tableName = "remote_keys")
data class RemoteKeys(
@PrimaryKey val entityId: Int,
@TypeConverters(RemoteKeyType::class)
val type: RemoteKeyType,
val prevKey: Int?,
val nextKey: Int?
)
enum class RemoteKeyType(private val type: String) {
USER(User::class.simpleName ?: "User"),
PIZZA(Pizza::class.simpleName ?: "Pizza"),
ORDER(Order::class.simpleName ?: "Order"),
BASKET(Basket::class.simpleName ?: "Basket");
@TypeConverter
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
@TypeConverter
fun fromRemoteKeyType(value: RemoteKeyType) = value.type
}

View File

@ -0,0 +1,20 @@
package com.example.pizza.RemoteKeys
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Maybe
@Dao
interface RemoteKeysDao {
@Query("SELECT * FROM remote_keys WHERE entityId = :entityId AND type = :type")
fun getRemoteKeys(entityId: Int, type: RemoteKeyType): Maybe<RemoteKeys>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(remoteKey: List<RemoteKeys>) : Completable
@Query("DELETE FROM remote_keys WHERE type = :type")
fun clearRemoteKeys(type: RemoteKeyType) : Completable
}

View File

@ -14,9 +14,7 @@ object AppViewModelProvider {
initializer { initializer {
PizzaEditViewModel(studentApplication().container.pizzaRepository) PizzaEditViewModel(studentApplication().container.pizzaRepository)
} }
initializer {
UserViewModel(studentApplication().container.userRepository)
}
initializer { initializer {
BasketEditViewModel(studentApplication().container.basketRepository) BasketEditViewModel(studentApplication().container.basketRepository)
} }
@ -29,6 +27,9 @@ object AppViewModelProvider {
initializer { initializer {
OrderListViewModel(studentApplication().container.orderRepository) OrderListViewModel(studentApplication().container.orderRepository)
} }
initializer {
UserViewModel(studentApplication().container.userRepository)
}
} }
} }

View File

@ -4,15 +4,18 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.rxjava3.cachedIn import androidx.paging.rxjava3.cachedIn
import androidx.paging.rxjava3.flowable import androidx.paging.rxjava3.flowable
import com.example.pizza.Model.Basket.PizzaBasket import com.example.pizza.Model.Basket.PizzaBasket
import com.example.pizza.Model.Order.PizzaOrder import com.example.pizza.Model.Order.PizzaOrder
import com.example.pizza.Model.Repository.BasketRepository import com.example.pizza.Model.Repository.BasketRepository
import com.example.pizza.Model.Repository.OrderRepository import com.example.pizza.Model.Repository.OrderRepository
import com.example.pizza.Model.Repository.Rest.RestOrderRepository
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
@ -24,38 +27,33 @@ class OrderListViewModel(private val orderRepository: OrderRepository): ViewMode
private val pizzas: MutableLiveData<PagingData<PizzaOrder>?> = MutableLiveData() private val pizzas: MutableLiveData<PagingData<PizzaOrder>?> = MutableLiveData()
fun getPizzas(uid: Int): LiveData<PagingData<PizzaOrder>?> { fun getPizzas(uid: Int): LiveData<PagingData<PizzaOrder>?> {
if (pizzas.value == null) {
loadPizzas(uid) loadPizzas(uid)
}
return pizzas return pizzas
} }
private fun createPagingConfig(): PagingConfig {
@OptIn(ExperimentalCoroutinesApi::class, ExperimentalPagingApi::class)
private fun loadPizzas(uid: Int) {
val pageSize = 3 val pageSize = 3
val placeholders = true val placeholders = true
return PagingConfig( var config = PagingConfig(
pageSize, pageSize = pageSize,
pageSize, enablePlaceholders =placeholders
placeholders,
pageSize * 2,
pageSize + pageSize * 2, Int.MIN_VALUE
) )
} // val disposable = Pager(
// config = config,
// remoteMediator = (orderRepository as RestOrderRepository).mediator,
private fun loadPizzas(uid: Int) { // pagingSourceFactory = { orderRepository.getUserHistory(uid) }
val disposable = Pager( // ).flowable
config = createPagingConfig(), // .cachedIn(viewModelScope)
pagingSourceFactory = {orderRepository.getUserHistory(uid)} // .subscribeOn(Schedulers.io())
).flowable // .observeOn(AndroidSchedulers.mainThread())
.cachedIn(viewModelScope) // .doOnError({pizzas.value = null})
.subscribeOn(Schedulers.io()) // .subscribe { data ->
.observeOn(AndroidSchedulers.mainThread()) // pizzas.postValue(data)
.doOnError({pizzas.value = null}) // }
.subscribe { data -> // mDisposable.add(disposable)
pizzas.postValue(data)
}
mDisposable.add(disposable)
} }
override fun onCleared() { override fun onCleared() {

View File

@ -36,13 +36,13 @@ class PizzaEditViewModel(
mDisposable.add(disposable) mDisposable.add(disposable)
} }
fun savePizza(pizza: Pizza, onSave: () -> Unit) { fun savePizza(pizza: Pizza, onSave: () -> Unit,onError: () -> Unit) {
val completable: Completable = pizzaRepository.insert(pizza) val completable: Completable = pizzaRepository.insert(pizza)
val disposable = completable val disposable = completable
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ onSave() }) .subscribe({ onSave() },{onError()})
mDisposable.add(disposable) mDisposable.add(disposable)
} }
fun updatePizza(pizza: Pizza, onSave: () -> Unit, onError: () -> Unit) { fun updatePizza(pizza: Pizza, onSave: () -> Unit, onError: () -> Unit) {

View File

@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
@ -11,6 +12,7 @@ import androidx.paging.rxjava3.cachedIn
import androidx.paging.rxjava3.flowable import androidx.paging.rxjava3.flowable
import com.example.pizza.Model.Pizza.Pizza import com.example.pizza.Model.Pizza.Pizza
import com.example.pizza.Model.Repository.PizzaRepository import com.example.pizza.Model.Repository.PizzaRepository
import com.example.pizza.Model.Repository.Rest.RestPizzaRepository
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
@ -22,29 +24,26 @@ class PizzaListViewModel(private val pizzaRepository: PizzaRepository): ViewMode
private val pizzas: MutableLiveData<PagingData<Pizza>> = MutableLiveData() private val pizzas: MutableLiveData<PagingData<Pizza>> = MutableLiveData()
fun getPizzas(): LiveData<PagingData<Pizza>> { fun getPizzas(): LiveData<PagingData<Pizza>> {
if (pizzas.value == null) {
loadPizzas() loadPizzas()
}
return pizzas return pizzas
} }
private fun createPagingConfig(): PagingConfig {
@OptIn(ExperimentalCoroutinesApi::class, ExperimentalPagingApi::class)
private fun loadPizzas() {
var meditator = (pizzaRepository as RestPizzaRepository).mediator
var pagingSourceFactory = {pizzaRepository.getAll()}
val pageSize = 3 val pageSize = 3
val placeholders = true val placeholders = true
return PagingConfig( var config = PagingConfig(
pageSize, pageSize = pageSize,
pageSize, enablePlaceholders =placeholders
placeholders,
pageSize * 2,
pageSize + pageSize * 2, Int.MIN_VALUE
) )
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun loadPizzas() {
val disposable = Pager( val disposable = Pager(
config = createPagingConfig(), config = config,
pagingSourceFactory = pizzaRepository::getAll pagingSourceFactory = pagingSourceFactory,
remoteMediator = meditator,
).flowable ).flowable
.cachedIn(viewModelScope) .cachedIn(viewModelScope)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

View File

@ -87,6 +87,7 @@ class UserViewModel(
} }
override fun onCleared() { override fun onCleared() {
super.onCleared() super.onCleared()
mDisposable.clear() mDisposable.clear()

View File

@ -83,12 +83,15 @@ class create_pizza : Fragment() {
return return
} }
if(!editing) { if(!editing) {
pizzaViewModel!!.savePizza(pizza1) { pizzaViewModel!!.savePizza(pizza1,
onSave = {
Toast.makeText(view.context, "Пицца успешно добавлена", Toast.LENGTH_SHORT).show() Toast.makeText(view.context, "Пицца успешно добавлена", Toast.LENGTH_SHORT).show()
val action = create_pizzaDirections val action = create_pizzaDirections
.actionNavigationCreatePizzaToListNavigation() .actionNavigationCreatePizzaToListNavigation()
Navigation.findNavController(view).navigate(action) Navigation.findNavController(view).navigate(action)
} },
onError = {Toast.makeText(view.context, "Ошибка!!!", Toast.LENGTH_SHORT).show()}
)
} }
else else
{ {

View File

@ -8,7 +8,14 @@ import com.example.pizza.Model.Repository.OfflinePizzaRepository
import com.example.pizza.Model.Repository.OfflineUserRepository import com.example.pizza.Model.Repository.OfflineUserRepository
import com.example.pizza.Model.Repository.OrderRepository import com.example.pizza.Model.Repository.OrderRepository
import com.example.pizza.Model.Repository.PizzaRepository import com.example.pizza.Model.Repository.PizzaRepository
import com.example.pizza.Model.Repository.Rest.RestBasketRepository
import com.example.pizza.Model.Repository.Rest.RestOrderRepository
import com.example.pizza.Model.Repository.Rest.RestPizzaRepository
import com.example.pizza.Model.Repository.Rest.RestUserRepository
import com.example.pizza.Model.Repository.UserRepository import com.example.pizza.Model.Repository.UserRepository
import com.example.pizza.Model.Rest.MyServerService
import com.example.pizza.RemoteKeys.OfflineRemoteKeyRepository
import com.example.pizza.RemoteKeys.RemoteKeyRepository
interface AppContainer { interface AppContainer {
@ -16,20 +23,45 @@ interface AppContainer {
val userRepository: UserRepository val userRepository: UserRepository
val basketRepository: BasketRepository val basketRepository: BasketRepository
val orderRepository : OrderRepository val orderRepository : OrderRepository
val remoteKeyRepository: RemoteKeyRepository
} }
class AppDataContainer(private val context: Context) : AppContainer { class AppDataContainer(private val context: Context) : AppContainer {
override val pizzaRepository: PizzaRepository by lazy { override val pizzaRepository: PizzaRepository by lazy {
OfflinePizzaRepository(AppDatabase.getInstance(context).pizzaDao()) RestPizzaRepository(
MyServerService.getInstance(),
OfflinePizzaRepository(AppDatabase.getInstance(context).pizzaDao()),
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao()),
AppDatabase.getInstance(context))
} }
override val userRepository: UserRepository by lazy { override val userRepository: UserRepository by lazy {
OfflineUserRepository(AppDatabase.getInstance(context).userDao()) RestUserRepository(
MyServerService.getInstance(),
OfflineUserRepository(AppDatabase.getInstance(context).userDao()),
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao()),
AppDatabase.getInstance(context)
)
} }
override val basketRepository: BasketRepository by lazy { override val basketRepository: BasketRepository by lazy {
OfflineBasketRepository(AppDatabase.getInstance(context).basketDao()) RestBasketRepository(
MyServerService.getInstance(),
OfflineBasketRepository(AppDatabase.getInstance(context).basketDao()),
OfflinePizzaRepository(AppDatabase.getInstance(context).pizzaDao()),
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao()),
AppDatabase.getInstance(context))
} }
override val orderRepository: OrderRepository by lazy { override val orderRepository: OrderRepository by lazy {
OfflineOrderRepository(AppDatabase.getInstance(context).orderDao()) RestOrderRepository(
MyServerService.getInstance(),
OfflineOrderRepository(AppDatabase.getInstance(context).orderDao()),
OfflinePizzaRepository(AppDatabase.getInstance(context).pizzaDao()),
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao()),
AppDatabase.getInstance(context))
}
override val remoteKeyRepository: RemoteKeyRepository by lazy {
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao())
} }

View File

@ -26,22 +26,30 @@ import com.example.pizza.Model.Pizza.PizzaDao
import com.example.pizza.Model.Pizza.Singleton import com.example.pizza.Model.Pizza.Singleton
import com.example.pizza.Model.User.User import com.example.pizza.Model.User.User
import com.example.pizza.Model.User.UserDao import com.example.pizza.Model.User.UserDao
import com.example.pizza.RemoteKeys.RemoteKeys
import com.example.pizza.RemoteKeys.RemoteKeysDao
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.concurrent.Executors import java.util.concurrent.Executors
@Database(entities = [User::class, Pizza::class,Basket::class,Order::class], version = 1, exportSchema = false) @Database(entities = [
User::class,
Pizza::class,
Basket::class,
Order::class,
RemoteKeys::class,
], version = 1, exportSchema = false)
@TypeConverters(ImageConverter::class, DateConverter::class) @TypeConverters(ImageConverter::class, DateConverter::class)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao abstract fun userDao(): UserDao
abstract fun pizzaDao(): PizzaDao abstract fun pizzaDao(): PizzaDao
abstract fun basketDao(): BasketDao abstract fun basketDao(): BasketDao
abstract fun orderDao(): OrderDao abstract fun orderDao(): OrderDao
abstract fun remoteKeysDao(): RemoteKeysDao
companion object { companion object {
private const val DB_NAME: String = "dp9" private const val DB_NAME: String = "dp11"
@Volatile @Volatile
private var INSTANCE: AppDatabase? = null private var INSTANCE: AppDatabase? = null
@ -101,7 +109,7 @@ abstract class AppDatabase : RoomDatabase() {
.addCallback(object : Callback() { .addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) { override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db) super.onCreate(db)
Executors.newSingleThreadExecutor().execute { populateDatabase() } //Executors.newSingleThreadExecutor().execute { populateDatabase() }
} }
}) })
.build() .build()

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true"/>
</network-security-config>