Feature: add pagging, connect to API
This commit is contained in:
parent
2f99f363c0
commit
6b41efd82e
@ -2,6 +2,7 @@ plugins {
|
|||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
id("org.jetbrains.kotlin.android")
|
id("org.jetbrains.kotlin.android")
|
||||||
id ("kotlin-kapt")
|
id ("kotlin-kapt")
|
||||||
|
kotlin("plugin.serialization") version "1.4.21"
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package com.example.android_programming
|
package com.example.android_programming
|
||||||
|
|
||||||
|
import com.example.android_programming.api.repository.RestSneakerRepository
|
||||||
|
import com.example.android_programming.api.repository.RestUserRepository
|
||||||
import com.example.android_programming.repository.BasketRepository
|
import com.example.android_programming.repository.BasketRepository
|
||||||
import com.example.android_programming.repository.OrderRepository
|
import com.example.android_programming.repository.OrderRepository
|
||||||
import com.example.android_programming.repository.SneakerRepository
|
import com.example.android_programming.repository.SneakerRepository
|
||||||
import com.example.android_programming.repository.UserRepository
|
import com.example.android_programming.repository.UserRepository
|
||||||
|
|
||||||
interface AppContainer {
|
interface AppContainer {
|
||||||
val sneakerRepo: SneakerRepository
|
val sneakerRepo: RestSneakerRepository
|
||||||
val userRepo: UserRepository
|
val userRepo: RestUserRepository
|
||||||
val orderRepo: OrderRepository
|
val orderRepo: OrderRepository
|
||||||
val basketRepo: BasketRepository
|
val basketRepo: BasketRepository
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TIMEOUT = 5000L
|
||||||
|
const val LIMIT = 10
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,7 +1,11 @@
|
|||||||
package com.example.android_programming
|
package com.example.android_programming
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.example.android_programming.api.BackendService
|
||||||
|
import com.example.android_programming.api.repository.RestSneakerRepository
|
||||||
|
import com.example.android_programming.api.repository.RestUserRepository
|
||||||
import com.example.android_programming.database.AppDatabase
|
import com.example.android_programming.database.AppDatabase
|
||||||
|
import com.example.android_programming.database.remotekeys.repository.RemoteKeysRepositoryImpl
|
||||||
import com.example.android_programming.repository.BasketRepoImpl
|
import com.example.android_programming.repository.BasketRepoImpl
|
||||||
import com.example.android_programming.repository.BasketRepository
|
import com.example.android_programming.repository.BasketRepository
|
||||||
import com.example.android_programming.repository.OrderRepoImpl
|
import com.example.android_programming.repository.OrderRepoImpl
|
||||||
@ -12,11 +16,16 @@ import com.example.android_programming.repository.UserRepoImpl
|
|||||||
import com.example.android_programming.repository.UserRepository
|
import com.example.android_programming.repository.UserRepository
|
||||||
|
|
||||||
class AppDataContainer(private val context: Context) : AppContainer {
|
class AppDataContainer(private val context: Context) : AppContainer {
|
||||||
override val sneakerRepo: SneakerRepository by lazy {
|
override val sneakerRepo: RestSneakerRepository by lazy {
|
||||||
SneakerRepoImpl(AppDatabase.getInstance(context).sneakerDao())
|
RestSneakerRepository(
|
||||||
|
BackendService.getInstance(),
|
||||||
|
sneakerRepository,
|
||||||
|
AppDatabase.getInstance(context),
|
||||||
|
remoteKeyRepository
|
||||||
|
)
|
||||||
}
|
}
|
||||||
override val userRepo: UserRepository by lazy {
|
override val userRepo: RestUserRepository by lazy {
|
||||||
UserRepoImpl(AppDatabase.getInstance(context).userDao())
|
RestUserRepository(BackendService.getInstance())
|
||||||
}
|
}
|
||||||
override val orderRepo: OrderRepository by lazy {
|
override val orderRepo: OrderRepository by lazy {
|
||||||
OrderRepoImpl(AppDatabase.getInstance(context).orderDao())
|
OrderRepoImpl(AppDatabase.getInstance(context).orderDao())
|
||||||
@ -24,4 +33,10 @@ class AppDataContainer(private val context: Context) : AppContainer {
|
|||||||
override val basketRepo: BasketRepository by lazy {
|
override val basketRepo: BasketRepository by lazy {
|
||||||
BasketRepoImpl(AppDatabase.getInstance(context).basketDao())
|
BasketRepoImpl(AppDatabase.getInstance(context).basketDao())
|
||||||
}
|
}
|
||||||
|
private val sneakerRepository: SneakerRepoImpl by lazy {
|
||||||
|
SneakerRepoImpl(AppDatabase.getInstance(context).sneakerDao())
|
||||||
|
}
|
||||||
|
private val remoteKeyRepository: RemoteKeysRepositoryImpl by lazy {
|
||||||
|
RemoteKeysRepositoryImpl(AppDatabase.getInstance(context).remoteKeysDao())
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.example.android_programming.api
|
||||||
|
|
||||||
|
import com.example.android_programming.api.model.SneakerRemote
|
||||||
|
import com.example.android_programming.api.model.UserRemote
|
||||||
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
interface BackendService {
|
||||||
|
|
||||||
|
//SNEAKER
|
||||||
|
@GET("sneaker/get/{id}")
|
||||||
|
suspend fun getSneaker(
|
||||||
|
@Path("id") id: Int,
|
||||||
|
): SneakerRemote
|
||||||
|
|
||||||
|
@GET("sneaker/getAll")
|
||||||
|
suspend fun getSneakers(
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
): List<SneakerRemote>
|
||||||
|
|
||||||
|
//USER
|
||||||
|
@POST("user/signup")
|
||||||
|
suspend fun SignUp(
|
||||||
|
@Body user: UserRemote,
|
||||||
|
): UserRemote
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL = "https://59k4pfj3-8080.euw.devtunnels.ms/api/"
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var INSTANCE: BackendService? = null
|
||||||
|
|
||||||
|
fun getInstance(): BackendService {
|
||||||
|
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(BackendService::class.java)
|
||||||
|
.also { INSTANCE = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
package com.example.android_programming.api
|
||||||
|
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.LoadType
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import androidx.paging.RemoteMediator
|
||||||
|
import androidx.room.withTransaction
|
||||||
|
import com.example.android_programming.api.model.toSneaker
|
||||||
|
import com.example.android_programming.api.repository.RestSneakerRepository
|
||||||
|
import com.example.android_programming.database.AppDatabase
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeyType
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeys
|
||||||
|
import com.example.android_programming.database.remotekeys.repository.RemoteKeyRepository
|
||||||
|
import com.example.android_programming.database.remotekeys.repository.RemoteKeysRepositoryImpl
|
||||||
|
import com.example.android_programming.model.Sneaker
|
||||||
|
import com.example.android_programming.repository.SneakerRepoImpl
|
||||||
|
import com.example.android_programming.repository.SneakerRepository
|
||||||
|
import retrofit2.HttpException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
class SneakerRemoteMediator(
|
||||||
|
private val service: BackendService,
|
||||||
|
private val sneakerRepository: SneakerRepoImpl,
|
||||||
|
private val database: AppDatabase,
|
||||||
|
private val dbRemoteKeyRepository:RemoteKeysRepositoryImpl
|
||||||
|
) : RemoteMediator<Int, Sneaker>() {
|
||||||
|
override suspend fun initialize(): InitializeAction {
|
||||||
|
return InitializeAction.LAUNCH_INITIAL_REFRESH
|
||||||
|
}
|
||||||
|
override suspend fun load(
|
||||||
|
loadType: LoadType,
|
||||||
|
state: PagingState<Int, Sneaker>
|
||||||
|
): 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 sneakers = service.getSneakers(page, state.config.pageSize).map { it.toSneaker() }
|
||||||
|
val endOfPaginationReached = sneakers.isEmpty()
|
||||||
|
database.withTransaction {
|
||||||
|
if (loadType == LoadType.REFRESH) {
|
||||||
|
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.SNEAKER)
|
||||||
|
sneakerRepository.clearSneakers()
|
||||||
|
}
|
||||||
|
val prevKey = if (page == 1) null else page - 1
|
||||||
|
val nextKey = if (endOfPaginationReached) null else page + 1
|
||||||
|
val keys = sneakers.map {
|
||||||
|
RemoteKeys(
|
||||||
|
entityId = it.sneakerId!!,
|
||||||
|
type = RemoteKeyType.SNEAKER,
|
||||||
|
prevKey = prevKey,
|
||||||
|
nextKey = nextKey
|
||||||
|
)
|
||||||
|
}
|
||||||
|
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||||
|
sneakerRepository.insertSneakers(sneakers)
|
||||||
|
}
|
||||||
|
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, Sneaker>): RemoteKeys? {
|
||||||
|
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
|
||||||
|
?.let { sneaker ->
|
||||||
|
sneaker.sneakerId?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.SNEAKER) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Sneaker>): RemoteKeys? {
|
||||||
|
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
|
||||||
|
?.let { sneaker ->
|
||||||
|
sneaker.sneakerId?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.SNEAKER) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getRemoteKeyClosestToCurrentPosition(
|
||||||
|
state: PagingState<Int, Sneaker>
|
||||||
|
): RemoteKeys? {
|
||||||
|
return state.anchorPosition?.let { position ->
|
||||||
|
state.closestItemToPosition(position)?.sneakerId?.let { sneakerUid ->
|
||||||
|
dbRemoteKeyRepository.getAllRemoteKeys(sneakerUid, RemoteKeyType.SNEAKER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.example.android_programming.api.model
|
||||||
|
|
||||||
|
import com.example.android_programming.model.Sneaker
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SneakerRemote (
|
||||||
|
val id: Int? = 0,
|
||||||
|
val brand: String = "",
|
||||||
|
val model: String = "",
|
||||||
|
val description: String = "",
|
||||||
|
val price: Double = 0.0,
|
||||||
|
val photo: Int = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
fun SneakerRemote.toSneaker():Sneaker = Sneaker(
|
||||||
|
id,
|
||||||
|
brand,
|
||||||
|
model,
|
||||||
|
description,
|
||||||
|
price,
|
||||||
|
photo
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Sneaker.toSneakerRemote():SneakerRemote = SneakerRemote(
|
||||||
|
sneakerId,
|
||||||
|
brand,
|
||||||
|
model,
|
||||||
|
description,
|
||||||
|
price,
|
||||||
|
photo
|
||||||
|
)
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.example.android_programming.api.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.example.android_programming.model.RoleEnum
|
||||||
|
import com.example.android_programming.model.Sneaker
|
||||||
|
import com.example.android_programming.model.User
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class UserRemote (
|
||||||
|
val id: Int? = 0,
|
||||||
|
val name: String = "",
|
||||||
|
val surname: String = "",
|
||||||
|
val email: String = "",
|
||||||
|
val password: String = "",
|
||||||
|
val role: RoleEnum = RoleEnum.User,
|
||||||
|
val photo: Int? = 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun UserRemote.toUser(): User = User(
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
surname,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
role,
|
||||||
|
photo
|
||||||
|
)
|
||||||
|
|
||||||
|
fun User.toUserRemote():UserRemote = UserRemote(
|
||||||
|
userId,
|
||||||
|
name,
|
||||||
|
surname,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
role,
|
||||||
|
photo
|
||||||
|
)
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.example.android_programming.api.repository
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import com.example.android_programming.AppContainer
|
||||||
|
import com.example.android_programming.api.BackendService
|
||||||
|
import com.example.android_programming.api.SneakerRemoteMediator
|
||||||
|
import com.example.android_programming.api.model.toSneaker
|
||||||
|
import com.example.android_programming.database.AppDatabase
|
||||||
|
import com.example.android_programming.database.remotekeys.repository.RemoteKeysRepositoryImpl
|
||||||
|
import com.example.android_programming.model.Sneaker
|
||||||
|
import com.example.android_programming.repository.SneakerRepoImpl
|
||||||
|
import com.example.android_programming.repository.SneakerRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
class RestSneakerRepository(
|
||||||
|
private val service: BackendService,
|
||||||
|
private val dbSneakerRepository: SneakerRepoImpl,
|
||||||
|
private val database: AppDatabase,
|
||||||
|
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
|
||||||
|
|
||||||
|
) : SneakerRepository {
|
||||||
|
|
||||||
|
override fun getAllSneakers(): Flow<PagingData<Sneaker>> {
|
||||||
|
val pagingSourceFactory = { dbSneakerRepository.getAllSneakersPagingSource() }
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
|
return Pager(
|
||||||
|
config = PagingConfig(
|
||||||
|
pageSize = AppContainer.LIMIT,
|
||||||
|
enablePlaceholders = false
|
||||||
|
),
|
||||||
|
remoteMediator = SneakerRemoteMediator(
|
||||||
|
service,
|
||||||
|
dbSneakerRepository,
|
||||||
|
database,
|
||||||
|
dbRemoteKeyRepository,
|
||||||
|
),
|
||||||
|
pagingSourceFactory = pagingSourceFactory
|
||||||
|
).flow
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSneakerById(id: Int): Sneaker = service.getSneaker(id).toSneaker()
|
||||||
|
override suspend fun insertSneaker(sneaker: Sneaker) {
|
||||||
|
print("sdfsd")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateSneaker(sneaker: Sneaker) {
|
||||||
|
print("sdfsd")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteSneaker(sneaker: Sneaker) {
|
||||||
|
print("sdfsd")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.example.android_programming.api.repository
|
||||||
|
|
||||||
|
import com.example.android_programming.api.BackendService
|
||||||
|
import com.example.android_programming.api.model.toUserRemote
|
||||||
|
import com.example.android_programming.model.User
|
||||||
|
import com.example.android_programming.repository.UserRepository
|
||||||
|
|
||||||
|
class RestUserRepository(
|
||||||
|
private var service: BackendService
|
||||||
|
): UserRepository {
|
||||||
|
override suspend fun createUser(user: User) {
|
||||||
|
val user1 = user.toUserRemote()
|
||||||
|
service.SignUp(user1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun updateUser(user: User) {
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteUser(user: User) {
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -36,7 +36,7 @@ import kotlinx.coroutines.delay
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChangePanel(navHostController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
fun ChangePanel(navHostController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||||
val list = sneakerViewModel.sneakerList.collectAsLazyPagingItems()
|
// val list = sneakerViewModel.sneakerList.collectAsLazyPagingItems()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -44,18 +44,18 @@ fun ChangePanel(navHostController: NavHostController, sneakerViewModel: SneakerV
|
|||||||
.background(Color.White)
|
.background(Color.White)
|
||||||
.padding(16.dp, 80.dp)
|
.padding(16.dp, 80.dp)
|
||||||
) {
|
) {
|
||||||
Row {
|
// Row {
|
||||||
LazyColumn(
|
// LazyColumn(
|
||||||
modifier = Modifier
|
// modifier = Modifier
|
||||||
.fillMaxSize()
|
// .fillMaxSize()
|
||||||
) {
|
// ) {
|
||||||
items(list.itemCount) { index ->
|
// items(list.itemCount) { index ->
|
||||||
list[index]?.let { sneaker ->
|
// list[index]?.let { sneaker ->
|
||||||
CardSneakerForChange(item = sneaker, navController = navHostController)
|
// CardSneakerForChange(item = sneaker, navController = navHostController)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,17 +5,28 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import androidx.paging.compose.itemKey
|
import androidx.paging.compose.itemKey
|
||||||
|
import com.example.android_programming.R
|
||||||
import com.example.android_programming.model.Sneaker
|
import com.example.android_programming.model.Sneaker
|
||||||
import com.example.android_programming.vmodel.AppViewModelProvider
|
import com.example.android_programming.vmodel.AppViewModelProvider
|
||||||
import com.example.android_programming.vmodel.OrderViewModel
|
import com.example.android_programming.vmodel.OrderViewModel
|
||||||
import com.example.android_programming.vmodel.SneakerViewModel
|
import com.example.android_programming.vmodel.SneakerViewModel
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RecyclerView(navHostController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
fun RecyclerView(navHostController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||||
|
@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
@Dao
|
@Dao
|
||||||
interface SneakerDao {
|
interface SneakerDao {
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insert(sneaker: Sneaker)
|
suspend fun insert(vararg sneaker: Sneaker)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
suspend fun update(sneaker: Sneaker)
|
suspend fun update(sneaker: Sneaker)
|
||||||
@ -22,7 +22,10 @@ interface SneakerDao {
|
|||||||
|
|
||||||
@Query("SELECT*FROM Sneaker")
|
@Query("SELECT*FROM Sneaker")
|
||||||
fun getAllSneakersPaged(): PagingSource<Int, Sneaker>
|
fun getAllSneakersPaged(): PagingSource<Int, Sneaker>
|
||||||
|
@Query("select * from Sneaker")
|
||||||
|
fun getAll(): PagingSource<Int, Sneaker>
|
||||||
@Query("SELECT * FROM Sneaker WHERE sneakerId = :id")
|
@Query("SELECT * FROM Sneaker WHERE sneakerId = :id")
|
||||||
suspend fun getSneakerById(id: Int): Sneaker
|
suspend fun getSneakerById(id: Int): Sneaker
|
||||||
|
@Query("DELETE FROM Sneaker")
|
||||||
|
suspend fun deleteAll()
|
||||||
}
|
}
|
@ -10,6 +10,8 @@ import com.example.android_programming.dao.BasketDao
|
|||||||
import com.example.android_programming.dao.OrderDao
|
import com.example.android_programming.dao.OrderDao
|
||||||
import com.example.android_programming.dao.SneakerDao
|
import com.example.android_programming.dao.SneakerDao
|
||||||
import com.example.android_programming.dao.UserDao
|
import com.example.android_programming.dao.UserDao
|
||||||
|
import com.example.android_programming.database.remotekeys.dao.RemoteKeysDao
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeys
|
||||||
import com.example.android_programming.model.Basket
|
import com.example.android_programming.model.Basket
|
||||||
import com.example.android_programming.model.BasketSneakers
|
import com.example.android_programming.model.BasketSneakers
|
||||||
import com.example.android_programming.model.Order
|
import com.example.android_programming.model.Order
|
||||||
@ -21,12 +23,13 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Database(entities = [Sneaker::class, User::class, Order::class, OrderSneaker::class, Basket::class, BasketSneakers::class], version = 6)
|
@Database(entities = [Sneaker::class, User::class, Order::class, OrderSneaker::class, Basket::class, BasketSneakers::class, RemoteKeys::class], version = 7)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract fun sneakerDao(): SneakerDao
|
abstract fun sneakerDao(): SneakerDao
|
||||||
abstract fun userDao(): UserDao
|
abstract fun userDao(): UserDao
|
||||||
abstract fun orderDao(): OrderDao
|
abstract fun orderDao(): OrderDao
|
||||||
abstract fun basketDao(): BasketDao
|
abstract fun basketDao(): BasketDao
|
||||||
|
abstract fun remoteKeysDao(): RemoteKeysDao
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DB_NAME: String = "my-db"
|
private const val DB_NAME: String = "my-db"
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.android_programming.database.remotekeys.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeyType
|
||||||
|
import com.example.android_programming.database.remotekeys.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)
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.example.android_programming.database.remotekeys.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
import com.example.android_programming.model.Sneaker
|
||||||
|
|
||||||
|
enum class RemoteKeyType(private val type: String) {
|
||||||
|
SNEAKER(Sneaker::class.simpleName ?: "Sneaker");
|
||||||
|
@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?
|
||||||
|
)
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.android_programming.database.remotekeys.repository
|
||||||
|
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeyType
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeys
|
||||||
|
|
||||||
|
interface RemoteKeyRepository {
|
||||||
|
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
|
||||||
|
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
|
||||||
|
suspend fun deleteRemoteKey(type: RemoteKeyType)
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.example.android_programming.database.remotekeys.repository
|
||||||
|
|
||||||
|
import com.example.android_programming.database.remotekeys.dao.RemoteKeysDao
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeyType
|
||||||
|
import com.example.android_programming.database.remotekeys.model.RemoteKeys
|
||||||
|
|
||||||
|
class RemoteKeysRepositoryImpl(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)
|
||||||
|
}
|
@ -5,6 +5,7 @@ import androidx.paging.PagingConfig
|
|||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.PagingSource
|
import androidx.paging.PagingSource
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
|
import com.example.android_programming.AppContainer
|
||||||
import com.example.android_programming.dao.SneakerDao
|
import com.example.android_programming.dao.SneakerDao
|
||||||
import com.example.android_programming.model.Sneaker
|
import com.example.android_programming.model.Sneaker
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -18,12 +19,25 @@ class SneakerRepoImpl(private val sneakerDao: SneakerDao) : SneakerRepository {
|
|||||||
override suspend fun deleteSneaker(sneaker: Sneaker) = sneakerDao.delete(sneaker)
|
override suspend fun deleteSneaker(sneaker: Sneaker) = sneakerDao.delete(sneaker)
|
||||||
|
|
||||||
override suspend fun getSneakerById(id: Int): Sneaker = sneakerDao.getSneakerById(id)
|
override suspend fun getSneakerById(id: Int): Sneaker = sneakerDao.getSneakerById(id)
|
||||||
override fun getAllSneakersPaged(): PagingSource<Int, Sneaker> = sneakerDao.getAllSneakersPaged()
|
override fun getAllSneakers(): Flow<PagingData<Sneaker>> = Pager(
|
||||||
override fun call(): Flow<PagingData<Sneaker>> {
|
config = PagingConfig(
|
||||||
return Pager(
|
pageSize = AppContainer.LIMIT,
|
||||||
PagingConfig(pageSize = 5)
|
enablePlaceholders = false
|
||||||
) {
|
),
|
||||||
sneakerDao.getAllSneakersPaged()
|
pagingSourceFactory = sneakerDao::getAll
|
||||||
}.flow
|
).flow
|
||||||
}
|
|
||||||
|
suspend fun clearSneakers() = sneakerDao.deleteAll()
|
||||||
|
suspend fun insertSneakers(sneakers: List<Sneaker>) =
|
||||||
|
sneakerDao.insert(*sneakers.toTypedArray())
|
||||||
|
|
||||||
|
fun getAllSneakersPagingSource(): PagingSource<Int, Sneaker> = sneakerDao.getAll()
|
||||||
|
// override fun getAllSneakersPaged(): PagingSource<Int, Sneaker> = sneakerDao.getAllSneakersPaged()
|
||||||
|
// override fun call(): Flow<PagingData<Sneaker>> {
|
||||||
|
// return Pager(
|
||||||
|
// PagingConfig(pageSize = 5)
|
||||||
|
// ) {
|
||||||
|
// sneakerDao.getAllSneakersPaged()
|
||||||
|
// }.flow
|
||||||
|
// }
|
||||||
}
|
}
|
@ -10,6 +10,5 @@ interface SneakerRepository {
|
|||||||
suspend fun updateSneaker(sneaker: Sneaker)
|
suspend fun updateSneaker(sneaker: Sneaker)
|
||||||
suspend fun deleteSneaker(sneaker: Sneaker)
|
suspend fun deleteSneaker(sneaker: Sneaker)
|
||||||
suspend fun getSneakerById(id: Int): Sneaker
|
suspend fun getSneakerById(id: Int): Sneaker
|
||||||
fun getAllSneakersPaged(): PagingSource<Int, Sneaker>
|
fun getAllSneakers(): Flow<PagingData<Sneaker>>
|
||||||
fun call(): Flow<PagingData<Sneaker>>
|
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ class UserRepoImpl(private val userDao: UserDao) : UserRepository {
|
|||||||
|
|
||||||
override suspend fun deleteUser(user: User) = userDao.deleteUser(user)
|
override suspend fun deleteUser(user: User) = userDao.deleteUser(user)
|
||||||
|
|
||||||
override suspend fun getUserById(id: Int): User = userDao.getUserById(id)
|
// override suspend fun getUserById(id: Int): User = userDao.getUserById(id)
|
||||||
|
//
|
||||||
override suspend fun getUserByEmail(email: String): User = userDao.getUserByEmail(email)
|
// override suspend fun getUserByEmail(email: String): User = userDao.getUserByEmail(email)
|
||||||
}
|
}
|
@ -9,6 +9,6 @@ interface UserRepository {
|
|||||||
suspend fun createUser(user: User)
|
suspend fun createUser(user: User)
|
||||||
suspend fun updateUser(user: User)
|
suspend fun updateUser(user: User)
|
||||||
suspend fun deleteUser(user: User)
|
suspend fun deleteUser(user: User)
|
||||||
suspend fun getUserById(id: Int): User
|
// suspend fun getUserById(id: Int): User
|
||||||
suspend fun getUserByEmail(email: String): User
|
// suspend fun getUserByEmail(email: String): User
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.example.android_programming.vmodel
|
package com.example.android_programming.vmodel
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -14,22 +16,27 @@ import androidx.paging.cachedIn
|
|||||||
import androidx.paging.map
|
import androidx.paging.map
|
||||||
import com.example.android_programming.App
|
import com.example.android_programming.App
|
||||||
import com.example.android_programming.R
|
import com.example.android_programming.R
|
||||||
|
import com.example.android_programming.api.model.toSneakerRemote
|
||||||
|
import com.example.android_programming.api.repository.RestSneakerRepository
|
||||||
import com.example.android_programming.database.AppDatabase
|
import com.example.android_programming.database.AppDatabase
|
||||||
import com.example.android_programming.model.Sneaker
|
import com.example.android_programming.model.Sneaker
|
||||||
import com.example.android_programming.repository.SneakerRepository
|
import com.example.android_programming.repository.SneakerRepository
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class SneakerViewModel(private val sneakerRepository: SneakerRepository): ViewModel() {
|
class SneakerViewModel(private val sneakerRepository: RestSneakerRepository): ViewModel() {
|
||||||
|
val sneakerList = sneakerRepository.getAllSneakers()
|
||||||
var brand = mutableStateOf("")
|
var brand = mutableStateOf("")
|
||||||
val model = mutableStateOf("")
|
val model = mutableStateOf("")
|
||||||
val description = mutableStateOf("")
|
val description = mutableStateOf("")
|
||||||
val price = mutableStateOf("")
|
val price = mutableStateOf("")
|
||||||
val photo = mutableIntStateOf(R.drawable.img)
|
val photo = mutableIntStateOf(R.drawable.img)
|
||||||
val sneakerList = sneakerRepository.call().cachedIn(viewModelScope)
|
|
||||||
var sneaker: Sneaker? = null
|
var sneaker: Sneaker? = null
|
||||||
|
private var _record = MutableStateFlow<Sneaker?>(null)
|
||||||
|
var record: StateFlow<Sneaker?> = _record
|
||||||
fun insertSneaker() = viewModelScope.launch {
|
fun insertSneaker() = viewModelScope.launch {
|
||||||
val sneaker = Sneaker(
|
val sneaker = Sneaker(
|
||||||
brand = brand.value,
|
brand = brand.value,
|
||||||
@ -45,10 +52,6 @@ class SneakerViewModel(private val sneakerRepository: SneakerRepository): ViewMo
|
|||||||
sneakerRepository.deleteSneaker(sneaker)
|
sneakerRepository.deleteSneaker(sneaker)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSneakerById(id: Int) = viewModelScope.launch {
|
|
||||||
sneakerRepository.getSneakerById(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun UpdateSneaker(sneaker: Sneaker) = viewModelScope.launch {
|
fun UpdateSneaker(sneaker: Sneaker) = viewModelScope.launch {
|
||||||
sneakerRepository.updateSneaker(sneaker)
|
sneakerRepository.updateSneaker(sneaker)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import androidx.lifecycle.viewmodel.CreationExtras
|
import androidx.lifecycle.viewmodel.CreationExtras
|
||||||
import com.example.android_programming.App
|
import com.example.android_programming.App
|
||||||
import com.example.android_programming.GlobalUser
|
import com.example.android_programming.GlobalUser
|
||||||
|
import com.example.android_programming.R
|
||||||
import com.example.android_programming.database.AppDatabase
|
import com.example.android_programming.database.AppDatabase
|
||||||
import com.example.android_programming.model.Basket
|
import com.example.android_programming.model.Basket
|
||||||
import com.example.android_programming.model.RoleEnum
|
import com.example.android_programming.model.RoleEnum
|
||||||
@ -28,16 +29,17 @@ class UserViewModel(private val userRepository: UserRepository): ViewModel() {
|
|||||||
surname = surname.value,
|
surname = surname.value,
|
||||||
email = email.value,
|
email = email.value,
|
||||||
password = password.value,
|
password = password.value,
|
||||||
role = RoleEnum.User
|
role = RoleEnum.User,
|
||||||
|
photo = R.drawable.shailushai
|
||||||
)
|
)
|
||||||
userRepository.createUser(user)
|
userRepository.createUser(user)
|
||||||
}
|
}
|
||||||
fun authUser() = viewModelScope.launch {
|
fun authUser() = viewModelScope.launch {
|
||||||
val user = userRepository.getUserByEmail(email.value)
|
// val user = userRepository.getUserByEmail(email.value)
|
||||||
if (password.value != "" && user.password == password.value) {
|
// if (password.value != "" && user.password == password.value) {
|
||||||
val globalUser = GlobalUser.getInstance()
|
// val globalUser = GlobalUser.getInstance()
|
||||||
globalUser.setUser(user)
|
// globalUser.setUser(user)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isValidEmail(email: String): Boolean {
|
fun isValidEmail(email: String): Boolean {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user