some beginning

This commit is contained in:
zyzf 2023-12-11 20:49:31 +04:00
parent 638b9d6aaf
commit 7c3af23e3b
26 changed files with 629 additions and 53 deletions

View File

@ -76,7 +76,7 @@ dependencies {
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta02") implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta02")
implementation("androidx.compose.material3:material3:1.1.2") implementation("androidx.compose.material3:material3:1.1.2")
implementation("androidx.paging:paging-compose:3.2.1") implementation("androidx.paging:paging-compose:3.2.1")
implementation("eu.bambooapps:compose-material3-pullrefresh:1.0.0") implementation("eu.bambooapps:compose-material3-pullrefresh:1.0.1")
// Room // Room
val roomVersion = "2.6.1" val roomVersion = "2.6.1"

View File

@ -0,0 +1,66 @@
package com.zyzf.coffeepreorder.api
import com.zyzf.coffeepreorder.api.model.CoffeeRemote
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
interface MyServerService {
@GET("groups")
suspend fun getGroups(): List<GroupRemote>
@GET("coffee")
suspend fun getCoffees(
@Query("_page") page: Int,
@Query("_limit") limit: Int,
): List<CoffeeRemote>
@GET("coffee/{id}")
suspend fun getCoffee(
@Path("id") id: Int,
): CoffeeRemote
@POST("coffee")
suspend fun createCoffee(
@Body student: CoffeeRemote,
): CoffeeRemote
@PUT("coffee/{id}")
suspend fun updateCoffee(
@Path("id") id: Int,
@Body student: CoffeeRemote,
): CoffeeRemote
@DELETE("coffee/{id}")
suspend fun deleteCoffee(
@Path("id") id: Int,
): CoffeeRemote
companion object {
private const val BASE_URL = "http://10.120.175.105:8079/"
@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()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(MyServerService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,108 @@
package com.zyzf.coffeepreorder.api.coffee
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.model.toCoffee
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
import com.zyzf.coffeepreorder.database.model.RemoteKeys
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
import retrofit2.HttpException
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class CoffeeRemoteMediator(
private val service: MyServerService,
private val dbCoffeeRepository: OfflineCoffeeRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : RemoteMediator<Int, Coffee>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Coffee>
): MediatorResult {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
remoteKeys?.prevKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
remoteKeys?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
}
try {
val coffees = service.getCoffees(page, state.config.pageSize).map { it.toCoffee() }
val endOfPaginationReached = coffees.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.Coffee)
dbCoffeeRepository.clearCoffees()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = coffees.map {
RemoteKeys(
entityId = it.uid,
type = RemoteKeyType.Coffee,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
for (coffee in coffees) {
dbCoffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
}
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
return MediatorResult.Error(exception)
} catch (exception: HttpException) {
return MediatorResult.Error(exception)
}
}
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Coffee>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { coffee ->
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.Coffee)
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Coffee>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { coffee ->
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.Coffee)
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Coffee>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { coffeeUid ->
dbRemoteKeyRepository.getAllRemoteKeys(coffeeUid, RemoteKeyType.Coffee)
}
}
}
}

View File

@ -0,0 +1,60 @@
package com.zyzf.coffeepreorder.api.coffee
import android.util.Log
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.model.toCoffee
import com.zyzf.coffeepreorder.api.model.toCoffeeRemote
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
import kotlinx.coroutines.flow.Flow
class RestCoffeeRepository(
private val service: MyServerService,
private val dbCoffeeRepository: OfflineCoffeeRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : CoffeeRepository {
override fun getAll(): Flow<PagingData<Coffee>> {
Log.d(RestCoffeeRepository::class.simpleName, "Get coffees")
val pagingSourceFactory = { dbCoffeeRepository.getAllCoffeesPagingSource() }
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = CoffeeRemoteMediator(
service,
dbCoffeeRepository,
dbRemoteKeyRepository,
database,
),
pagingSourceFactory = pagingSourceFactory
).flow
}
override suspend fun getByUid(uid: Int): Coffee? =
service.getCoffee(uid).toCoffee()
override suspend fun insert(name: String, cost: Double, ingredients: String): Int {
return service.createCoffee(Coffee(name, cost, ingredients, null, 0).toCoffeeRemote()).toCoffee().uid
}
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? {
return service.updateCoffee(uid, Coffee(uid, name, cost, ingredients, cartId, count).toCoffeeRemote()).toCoffee().uid
}
override suspend fun delete(coffee: Coffee) {
service.deleteCoffee(coffee.uid).toCoffee()
}
}

View File

@ -0,0 +1,32 @@
package com.zyzf.coffeepreorder.api.model
import com.zyzf.coffeepreorder.database.model.Coffee
import kotlinx.serialization.Serializable
@Serializable
data class CoffeeRemote(
val id: Int = 0,
val name: String = "",
val cost: Double = 0.0,
val ingredients: String = "",
val cartId: Int? = 0,
val count: Int = 0
)
fun CoffeeRemote.toCoffee(): Coffee = Coffee(
id,
name,
cost,
ingredients,
cartId,
count
)
fun Coffee.toCoffeeRemote(): CoffeeRemote = CoffeeRemote(
uid,
name,
cost,
ingredients,
cartId,
count
)

View File

@ -0,0 +1,32 @@
package com.zyzf.coffeepreorder.api.model
import com.zyzf.coffeepreorder.database.model.User
import kotlinx.serialization.Serializable
@Serializable
data class UserRemote(
val id: Int = 0,
val login: String = "",
val fio: String = "",
val phone: String = "",
val password: String = "",
val role: String = "user"
)
fun UserRemote.toUser(): User = User(
id,
login,
fio,
phone,
password,
role
)
fun User.toUserRemote(): UserRemote = UserRemote(
uid,
login,
fio,
phone,
password,
role
)

View File

@ -0,0 +1,64 @@
package com.zyzf.coffeepreorder.api.user
import android.util.Log
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.coffee.CoffeeRemoteMediator
import com.zyzf.coffeepreorder.api.model.toCoffee
import com.zyzf.coffeepreorder.api.model.toCoffeeRemote
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
import com.zyzf.coffeepreorder.database.repository.OfflineUserRepository
import com.zyzf.coffeepreorder.database.repository.UserRepository
import kotlinx.coroutines.flow.Flow
class RestUserRepository(
private val service: MyServerService,
private val dbUserRepository: OfflineUserRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : UserRepository {
override fun getAll(): Flow<PagingData<User>> {
Log.d(RestUserRepository::class.simpleName, "Get users")
val pagingSourceFactory = { dbUserRepository.getAllUserPagingSource() }
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = UserRemoteMediator(
service,
dbUserRepository,
dbRemoteKeyRepository,
database,
),
pagingSourceFactory = pagingSourceFactory
).flow
}
override suspend fun getByUid(uid: Int): User? =
service.getUser(uid).toUser()
override suspend fun insert(name: String, cost: Double, ingredients: String): Int {
return service.createCoffee(Coffee(name, cost, ingredients, null, 0).toCoffeeRemote()).toCoffee().uid
}
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? {
return service.updateCoffee(uid, Coffee(uid, name, cost, ingredients, cartId, count).toCoffeeRemote()).toCoffee().uid
}
override suspend fun delete(coffee: Coffee) {
service.deleteCoffee(coffee.uid).toCoffee()
}
}

View File

@ -0,0 +1,110 @@
package com.zyzf.coffeepreorder.api.user
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.model.toCoffee
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
import com.zyzf.coffeepreorder.database.model.RemoteKeys
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
import com.zyzf.coffeepreorder.database.repository.OfflineUserRepository
import retrofit2.HttpException
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class UserRemoteMediator(
private val service: MyServerService,
private val dbUserRepository: OfflineUserRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : RemoteMediator<Int, User>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, User>
): MediatorResult {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
remoteKeys?.prevKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
remoteKeys?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
}
try {
val coffees = service.getUsers(page, state.config.pageSize).map { it.toCoffee() }
val endOfPaginationReached = coffees.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.User)
dbUserRepository.clearCoffees()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = coffees.map {
RemoteKeys(
entityId = it.uid,
type = RemoteKeyType.User,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
for (user in coffees) {
dbUserRepository.insert()
}
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
return MediatorResult.Error(exception)
} catch (exception: HttpException) {
return MediatorResult.Error(exception)
}
}
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, User>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { user ->
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.User)
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, User>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { user ->
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.User)
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, User>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { userUid ->
dbRemoteKeyRepository.getAllRemoteKeys(userUid, RemoteKeyType.User)
}
}
}
}

View File

@ -12,6 +12,11 @@ interface AppContainer {
val coffeeRepository: CoffeeRepository val coffeeRepository: CoffeeRepository
val userRepository: UserRepository val userRepository: UserRepository
val cartRepository: CartRepository val cartRepository: CartRepository
companion object {
const val TIMEOUT = 5000L
const val LIMIT = 10
}
} }
class AppDataContainer(private val context: Context) : AppContainer { class AppDataContainer(private val context: Context) : AppContainer {
@ -24,9 +29,4 @@ class AppDataContainer(private val context: Context) : AppContainer {
override val cartRepository: CartRepository by lazy { override val cartRepository: CartRepository by lazy {
OfflineCartRepository(AppDatabase.getInstance(context).cartDao()) OfflineCartRepository(AppDatabase.getInstance(context).cartDao())
} }
companion object {
const val TIMEOUT = 5000L
const val LIMIT = 10
}
} }

View File

@ -1,16 +1,24 @@
package com.zyzf.coffeepreorder.database.dao package com.zyzf.coffeepreorder.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Update import androidx.room.Update
import com.zyzf.coffeepreorder.database.model.Cart import com.zyzf.coffeepreorder.database.model.Cart
import com.zyzf.coffeepreorder.database.model.Coffee
@Dao @Dao
interface CartDao { interface CartDao {
@Query("select * from cart limit 1") @Query("select * from cart limit 1")
suspend fun get(): Cart suspend fun get(): Cart
@Query("select * from coffee where cart_id is not null and count > 0 order by name collate nocase asc")
fun getAllInCart(): PagingSource<Int, Coffee>
@Query("select sum(cost) from coffee where cart_id is not null and count > 0")
fun getSumInCart(): Double
@Insert @Insert
suspend fun insert(cart: Cart) suspend fun insert(cart: Cart)

View File

@ -5,28 +5,24 @@ import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Query import androidx.room.Query
import com.zyzf.coffeepreorder.database.model.Coffee import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
@Dao @Dao
interface CoffeeDao { interface CoffeeDao {
@Query("select * from coffee order by name collate nocase asc") @Query("select * from coffee order by name collate nocase asc")
fun getAll(): PagingSource<Int, Coffee> fun getAll(): PagingSource<Int, Coffee>
@Query("select * from coffee where cart_id is not null and count > 0 order by name collate nocase asc") @Query("select coffee.uid, name, cost, ingredients, cart_id, count from coffee where coffee.uid = :uid")
fun getAllInCart(): PagingSource<Int, Coffee> suspend fun getByUid(uid: Int): Coffee?
@Query("select sum(cost) from coffee where cart_id is not null and count > 0")
fun getSumInCart(): Double
@Query("select coffee.uid, name, cost, ingredients, cart_id, count, cart.uid as cart_uid from coffee left join cart on coffee.cart_id = cart.uid where coffee.uid = :uid")
suspend fun getByUid(uid: Int): CoffeeWithCart?
@Query("insert into coffee (name, cost, ingredients, count) values (:name, :cost, :ingredients, 0)") @Query("insert into coffee (name, cost, ingredients, count) values (:name, :cost, :ingredients, 0)")
suspend fun insert(name: String, cost: Double, ingredients: String): Long suspend fun insert(name: String, cost: Double, ingredients: String): Int
@Query("update coffee set name = :name, cost = :cost, ingredients = :ingredients, cart_id = :cartId, count = :count where uid = :uid") @Query("update coffee set name = :name, cost = :cost, ingredients = :ingredients, cart_id = :cartId, count = :count where uid = :uid")
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int?
@Delete @Delete
suspend fun delete(coffee: Coffee) suspend fun delete(coffee: Coffee)
@Query("delete from coffee")
suspend fun deleteAll()
} }

View File

@ -0,0 +1,20 @@
package com.zyzf.coffeepreorder.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
import com.zyzf.coffeepreorder.database.model.RemoteKeys
@Dao
interface RemoteKeysDao {
@Query("SELECT * FROM remote_keys WHERE entityId = :entityId AND type = :type")
suspend fun getRemoteKeys(entityId: Int, type: RemoteKeyType): RemoteKeys?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(remoteKey: List<RemoteKeys>)
@Query("DELETE FROM remote_keys WHERE type = :type")
suspend fun clearRemoteKeys(type: RemoteKeyType)
}

View File

@ -1,15 +1,17 @@
package com.zyzf.coffeepreorder.database.dao package com.zyzf.coffeepreorder.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.User import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface UserDao { interface UserDao {
@Query("select * from user") @Query("select * from user")
fun getAll(): Flow<List<User>> fun getAll(): PagingSource<Int, User>
@Query("select * from user where login = :login and password = :password") @Query("select * from user where login = :login and password = :password")
suspend fun tryLogin(login: String, password: String): User? suspend fun tryLogin(login: String, password: String): User?

View File

@ -1,11 +0,0 @@
package com.zyzf.coffeepreorder.database.model
import androidx.room.ColumnInfo
import androidx.room.Embedded
data class CoffeeWithCart(
@Embedded
val coffee: Coffee,
@ColumnInfo(name = "cart_uid")
val cartUid: Int
)

View File

@ -0,0 +1,26 @@
package com.zyzf.coffeepreorder.database.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
Coffee(Coffee::class.simpleName ?: "Coffee"),
User(User::class.simpleName ?: "User");
@TypeConverter
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
@TypeConverter
fun fromRemoteKeyType(value: RemoteKeyType) = value.type
}
@Entity(tableName = "remote_keys")
data class RemoteKeys(
@PrimaryKey val entityId: Int,
@TypeConverters(RemoteKeyType::class)
val type: RemoteKeyType,
val prevKey: Int?,
val nextKey: Int?
)

View File

@ -8,7 +8,7 @@ import androidx.room.PrimaryKey
@Entity(tableName = "user") @Entity(tableName = "user")
data class User( data class User(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
val uid: Int?, val uid: Int = 0,
@ColumnInfo(name = "login") @ColumnInfo(name = "login")
var login: String, var login: String,
@ColumnInfo(name = "fio") @ColumnInfo(name = "fio")
@ -27,7 +27,20 @@ data class User(
phone: String, phone: String,
password: String, password: String,
role: String role: String
) : this(null, login, fio, phone, password, role) ) : this(0, login, fio, phone, password, role)
companion object {
fun getUser(index: Int = 0): User {
return User(
index,
"",
"",
"",
"",
"user"
)
}
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true

View File

@ -1,10 +1,15 @@
package com.zyzf.coffeepreorder.database.repository package com.zyzf.coffeepreorder.database.repository
import androidx.paging.PagingData
import com.zyzf.coffeepreorder.database.model.Cart import com.zyzf.coffeepreorder.database.model.Cart
import com.zyzf.coffeepreorder.database.model.Coffee
import kotlinx.coroutines.flow.Flow
interface CartRepository { interface CartRepository {
suspend fun get(): Cart suspend fun get(): Cart
suspend fun insert(cart: Cart) suspend fun insert(cart: Cart)
fun getAllInCart(): Flow<PagingData<Coffee>>
fun getSumInCart(): Double
suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int) suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int)
suspend fun deleteCoffee(coffeeId: Int, count: Int) suspend fun deleteCoffee(coffeeId: Int, count: Int)
suspend fun update(cart: Cart) suspend fun update(cart: Cart)

View File

@ -2,15 +2,12 @@ package com.zyzf.coffeepreorder.database.repository
import androidx.paging.PagingData import androidx.paging.PagingData
import com.zyzf.coffeepreorder.database.model.Coffee import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface CoffeeRepository { interface CoffeeRepository {
fun getAll(): Flow<PagingData<Coffee>> fun getAll(): Flow<PagingData<Coffee>>
fun getAllInCart(): Flow<PagingData<Coffee>> suspend fun getByUid(uid: Int): Coffee?
fun getSumInCart(): Double suspend fun insert(name: String, cost: Double, ingredients: String): Int
suspend fun getByUid(uid: Int): CoffeeWithCart?
suspend fun insert(name: String, cost: Double, ingredients: String): Long
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int?
suspend fun delete(coffee: Coffee) suspend fun delete(coffee: Coffee)
} }

View File

@ -1,9 +1,23 @@
package com.zyzf.coffeepreorder.database.repository package com.zyzf.coffeepreorder.database.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.dao.CartDao import com.zyzf.coffeepreorder.database.dao.CartDao
import com.zyzf.coffeepreorder.database.model.Cart import com.zyzf.coffeepreorder.database.model.Cart
import com.zyzf.coffeepreorder.database.model.Coffee
import kotlinx.coroutines.flow.Flow
class OfflineCartRepository(private val cartDao: CartDao) : CartRepository { class OfflineCartRepository(private val cartDao: CartDao) : CartRepository {
override fun getAllInCart(): Flow<PagingData<Coffee>> = Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = cartDao::getAllInCart
).flow
override fun getSumInCart(): Double = cartDao.getSumInCart()
override suspend fun get(): Cart = cartDao.get() override suspend fun get(): Cart = cartDao.get()
override suspend fun insert(cart: Cart) = cartDao.insert(cart) override suspend fun insert(cart: Cart) = cartDao.insert(cart)
override suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int) = cartDao.insertCoffee(cartId, coffeeId, count) override suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int) = cartDao.insertCoffee(cartId, coffeeId, count)

View File

@ -3,30 +3,25 @@ package com.zyzf.coffeepreorder.database.repository
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 com.zyzf.coffeepreorder.database.AppDataContainer import androidx.paging.PagingSource
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.dao.CoffeeDao import com.zyzf.coffeepreorder.database.dao.CoffeeDao
import com.zyzf.coffeepreorder.database.model.Coffee import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class OfflineCoffeeRepository(private val coffeeDao: CoffeeDao) : CoffeeRepository { class OfflineCoffeeRepository(private val coffeeDao: CoffeeDao) : CoffeeRepository {
override fun getAll(): Flow<PagingData<Coffee>> = Pager( override fun getAll(): Flow<PagingData<Coffee>> = Pager(
config = PagingConfig( config = PagingConfig(
pageSize = AppDataContainer.LIMIT, pageSize = AppContainer.LIMIT,
enablePlaceholders = false enablePlaceholders = false
), ),
pagingSourceFactory = coffeeDao::getAll pagingSourceFactory = coffeeDao::getAll
).flow ).flow
override fun getAllInCart(): Flow<PagingData<Coffee>> = Pager(
config = PagingConfig( fun getAllCoffeesPagingSource(): PagingSource<Int, Coffee> = coffeeDao.getAll()
pageSize = AppDataContainer.LIMIT, suspend fun clearCoffees() = coffeeDao.deleteAll()
enablePlaceholders = false override suspend fun getByUid(uid: Int): Coffee? = coffeeDao.getByUid(uid)
), override suspend fun insert(name: String, cost: Double, ingredients: String): Int = coffeeDao.insert(name, cost, ingredients)
pagingSourceFactory = coffeeDao::getAllInCart
).flow
override fun getSumInCart(): Double = coffeeDao.getSumInCart()
override suspend fun getByUid(uid: Int): CoffeeWithCart? = coffeeDao.getByUid(uid)
override suspend fun insert(name: String, cost: Double, ingredients: String): Long = coffeeDao.insert(name, cost, ingredients)
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? = coffeeDao.update(uid, name, cost, ingredients, cartId, count) override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? = coffeeDao.update(uid, name, cost, ingredients, cartId, count)
override suspend fun delete(coffee: Coffee) = coffeeDao.delete(coffee) override suspend fun delete(coffee: Coffee) = coffeeDao.delete(coffee)
} }

View File

@ -0,0 +1,16 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.dao.RemoteKeysDao
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
import com.zyzf.coffeepreorder.database.model.RemoteKeys
class OfflineRemoteKeyRepository(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository {
override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
remoteKeysDao.getRemoteKeys(id, type)
override suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
remoteKeysDao.insertAll(remoteKeys)
override suspend fun deleteRemoteKey(type: RemoteKeyType) =
remoteKeysDao.clearRemoteKeys(type)
}

View File

@ -1,11 +1,24 @@
package com.zyzf.coffeepreorder.database.repository package com.zyzf.coffeepreorder.database.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.dao.UserDao import com.zyzf.coffeepreorder.database.dao.UserDao
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.User import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class OfflineUserRepository(private val userDao: UserDao) : UserRepository { class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
override fun getAll(): Flow<List<User>> = userDao.getAll() override fun getAll(): Flow<PagingData<User>> = Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = userDao::getAll
).flow
fun getAllUserPagingSource(): PagingSource<Int, User> = userDao.getAll()
override suspend fun tryLogin(login: String, password: String): User? = userDao.tryLogin(login, password) override suspend fun tryLogin(login: String, password: String): User? = userDao.tryLogin(login, password)
override suspend fun getByUid(uid: Int): User? = userDao.getByUid(uid) override suspend fun getByUid(uid: Int): User? = userDao.getByUid(uid)
override suspend fun getLogined(): User? = userDao.getLogined() override suspend fun getLogined(): User? = userDao.getLogined()

View File

@ -0,0 +1,10 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
import com.zyzf.coffeepreorder.database.model.RemoteKeys
interface RemoteKeyRepository {
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
suspend fun deleteRemoteKey(type: RemoteKeyType)
}

View File

@ -1,10 +1,11 @@
package com.zyzf.coffeepreorder.database.repository package com.zyzf.coffeepreorder.database.repository
import androidx.paging.PagingData
import com.zyzf.coffeepreorder.database.model.User import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface UserRepository { interface UserRepository {
fun getAll(): Flow<List<User>> fun getAll(): Flow<PagingData<User>>
suspend fun tryLogin(login: String, password: String): User? suspend fun tryLogin(login: String, password: String): User?
suspend fun getByUid(uid: Int): User? suspend fun getByUid(uid: Int): User?
suspend fun getLogined(): User? suspend fun getLogined(): User?

View File

@ -8,10 +8,9 @@ import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class CartViewModel( class CartViewModel(
private val coffeeRepository: CoffeeRepository,
private val cartRepository: CartRepository private val cartRepository: CartRepository
) : ViewModel() { ) : ViewModel() {
val coffeeListUiState: Flow<PagingData<Coffee>> = coffeeRepository.getAllInCart() val coffeeListUiState: Flow<PagingData<Coffee>> = cartRepository.getAllInCart()
suspend fun deleteCoffeeFromCart(coffee: Coffee) { suspend fun deleteCoffeeFromCart(coffee: Coffee) {
cartRepository.deleteCoffee(coffee.uid, 1) cartRepository.deleteCoffee(coffee.uid, 1)

View File

@ -36,7 +36,7 @@ class CoffeeListViewModel(
cart.uid?.let { cartRepository.insertCoffee(it, coffeeUid, 1) } cart.uid?.let { cartRepository.insertCoffee(it, coffeeUid, 1) }
} }
suspend fun createCoffee(coffee: Coffee, imageUri: Uri, context: Context) { suspend fun createCoffee(coffee: Coffee, imageUri: Uri, context: Context) {
val newCoffee: Long = coffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients) val newCoffee: Int = coffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
val inputStream = context.contentResolver.openInputStream(imageUri) val inputStream = context.contentResolver.openInputStream(imageUri)
val bitmap = BitmapFactory.decodeStream(inputStream) val bitmap = BitmapFactory.decodeStream(inputStream)