Compare commits

..

3 Commits
l4 ... l5

Author SHA1 Message Date
cf49e1750b Upload reports 2023-12-20 11:58:06 +04:00
702cf2d259 Complete lab 5 2023-12-20 11:21:54 +04:00
9dcc14add5 add rest reps and mediators 2023-12-14 11:49:24 +04:00
83 changed files with 1761 additions and 541 deletions

View File

@ -1,8 +1,8 @@
package com.example.testapp package com.example.testapp
import android.app.Application import android.app.Application
import com.example.testapp.room.AppContainer import com.example.testapp.data.room.AppContainer
import com.example.testapp.room.AppDataContainer import com.example.testapp.data.room.AppDataContainer
class CryptoDealApplication : Application() { class CryptoDealApplication : Application() {
lateinit var container: AppContainer lateinit var container: AppContainer

View File

@ -8,7 +8,7 @@ import androidx.activity.viewModels
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.example.testapp.designElem.SharedViewModel import com.example.testapp.viewModels.SharedViewModel
import com.example.testapp.graphs.RootNavigationGraph import com.example.testapp.graphs.RootNavigationGraph
import com.example.testapp.ui.theme.TestAppTheme import com.example.testapp.ui.theme.TestAppTheme
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider

View File

@ -0,0 +1,135 @@
package com.example.testapp.data.api
import com.example.testapp.data.api.model.CoinRemote
import com.example.testapp.data.api.model.DealRemote
import com.example.testapp.data.api.model.UserRemote
import com.example.testapp.data.api.model.WalletItemRemote
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.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
interface UserRequests {
/**
* <i>User Request interface</i>
* */
@GET("users")
suspend fun getUsers(): List<UserRemote>
@GET("users/{id}")
suspend fun getUserById(@Path("id") id: Int): UserRemote
@POST("users")
suspend fun insert(@Body obj: UserRemote): UserRemote
@PUT("users/{id}")
suspend fun update(@Path("id") id: Int, @Body obj: UserRemote): UserRemote
@DELETE("users/{id}")
suspend fun deleteUser(@Path("id") id: Int): UserRemote
@GET("user_wallet/{id}")
suspend fun getUserWallet(@Path("id") id: Int): List<WalletItemRemote>
@GET("user_deal/{id}")
suspend fun getUserDeal(@Path("id") id: Int): List<DealRemote>
}
interface DealRequests {
/**
* <i>Deal Request interface</i>
*/
@GET("deals")
suspend fun getDeals(): List<DealRemote>
@GET("deals/{id}")
suspend fun getDealById(@Path("id") id: Int): DealRemote
@POST("deals")
suspend fun insert(@Body obj: DealRemote): DealRemote
@PUT("deals/{id}")
suspend fun update(@Path("id") id: Int, @Body obj: DealRemote): DealRemote
@DELETE("deals/{id}")
suspend fun deleteDeal(@Path("id") id: Int): DealRemote
@GET("deals")
suspend fun pagingDeals(
@Query("_page") page: Int,
@Query("_limit") limit: Int
): List<DealRemote>
@POST("complete_deal}")
suspend fun completeDeal(
@Query("dealId") dealId: Int,
@Query("sellerId")sellerId: Int,
@Query("buyerId") buyerId: Int,
): Boolean
}
interface CoinRequests {
/**
* <i>Coin Request interface</i>
*/
@GET("coins")
suspend fun getCoins(): List<CoinRemote>
}
interface WalletItemRequests {
/**
* <i>Wallet Item Request interface</i>
*/
@GET("wal_item")
suspend fun getWalletItems(): List<WalletItemRemote>
@POST("wal_item")
suspend fun insert(@Body obj: WalletItemRemote): WalletItemRemote
@PUT("wal_item/{id}")
suspend fun update(@Path("id") id: Int, @Body obj: WalletItemRemote): WalletItemRemote
@DELETE("wal_item/{id}")
suspend fun deleteWalletItem(@Path("id") id: Int): WalletItemRemote
@GET("wal_item")
suspend fun pagingWalletItems(
@Query("_page") page: Int,
@Query("_limit") limit: Int
): List<WalletItemRemote>
}
interface CryptoDealService : UserRequests, DealRequests, CoinRequests, WalletItemRequests {
companion object {
private const val BASE_URL = "http://172.20.10.13:8079/"
@Volatile
private var INSTANCE: CryptoDealService? = null
fun getInstance(): CryptoDealService {
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(CryptoDealService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,103 @@
package com.example.testapp.data.api.mediator
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.model.toDeal
import com.example.testapp.data.room.database.CryptoDealDb
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.models.RemoteKeyType
import com.example.testapp.data.room.models.RemoteKeys
import com.example.testapp.data.room.repository.offline.OfflineDealRepository
import com.example.testapp.data.room.repository.offline.OfflineRemoteKeyRepository
import okio.IOException
import retrofit2.HttpException
@OptIn(ExperimentalPagingApi::class)
class DealRemoteMediator(
private val service: CryptoDealService,
private val dbDealRepository: OfflineDealRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: CryptoDealDb
) : RemoteMediator<Int, Deal>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(loadType: LoadType, state: PagingState<Int, Deal>): 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 deals = service.pagingDeals(page, state.config.pageSize).map { it.toDeal() }
val endOfPaginationReached = deals.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.DEAL)
dbDealRepository.clearData()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = deals.map {
RemoteKeys(
entityId = it.id!!,
type = RemoteKeyType.DEAL,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
dbDealRepository.insert(deals)
}
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, Deal>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { art ->
art.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.DEAL) }
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Deal>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { art ->
art.id?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.DEAL) }
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Deal>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.id?.let { artid ->
dbRemoteKeyRepository.getAllRemoteKeys(artid, RemoteKeyType.DEAL)
}
}
}
}

View File

@ -0,0 +1,103 @@
package com.example.testapp.data.api.mediator
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.model.toWalletItem
import com.example.testapp.data.room.database.CryptoDealDb
import com.example.testapp.data.room.models.RemoteKeyType
import com.example.testapp.data.room.models.RemoteKeys
import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.data.room.repository.offline.OfflineRemoteKeyRepository
import com.example.testapp.data.room.repository.offline.OfflineWalletItemRepository
import okio.IOException
import retrofit2.HttpException
@OptIn(ExperimentalPagingApi::class)
class WalletItemRemoteMediator(
private val service: CryptoDealService,
private val dbWalletItemRepository: OfflineWalletItemRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: CryptoDealDb
) : RemoteMediator<Int, WalletItem>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(loadType: LoadType, state: PagingState<Int, WalletItem>): 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 articles = service.pagingWalletItems(page, state.config.pageSize).map { it.toWalletItem() }
val endOfPaginationReached = articles.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.WALLETITEM)
dbWalletItemRepository.clearData()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = articles.map {
RemoteKeys(
entityId = it.id!!,
type = RemoteKeyType.WALLETITEM,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
dbWalletItemRepository.insert(articles)
}
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, WalletItem>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { item ->
item.id!!.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.WALLETITEM) }
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, WalletItem>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { item ->
item.id!!.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.WALLETITEM) }
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, WalletItem>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.id?.let { itemId ->
dbRemoteKeyRepository.getAllRemoteKeys(itemId, RemoteKeyType.WALLETITEM)
}
}
}
}

View File

@ -0,0 +1,13 @@
package com.example.testapp.data.api.model
import com.example.testapp.data.room.models.Coin
import kotlinx.serialization.Serializable
@Serializable
data class CoinRemote(
val id: Int?,
val name: String
)
fun CoinRemote.toCoin(): Coin = Coin(id, name)
fun Coin.toRemote(): CoinRemote = CoinRemote(id, name)

View File

@ -0,0 +1,44 @@
package com.example.testapp.data.api.model
import com.example.testapp.data.room.models.Deal
import kotlinx.serialization.Serializable
@Serializable
data class DealRemote(
val id: Int?,
var sellerId: Int?,
val buyerId: Int?,
val sellerCoinId: Int,
val buyerCoinId: Int,
val countSell: Float,
val countBuy: Float,
val operation: String,
var date: Long?,
val tip: String
)
fun DealRemote.toDeal(): Deal = Deal(
id,
sellerId,
buyerId,
sellerCoinId,
buyerCoinId,
countSell,
countBuy,
operation,
date,
tip
)
fun Deal.toRemote(): DealRemote = DealRemote(
id,
sellerId,
buyerId,
sellerCoinId,
buyerCoinId,
countSell,
countBuy,
operation,
date,
tip
)

View File

@ -0,0 +1,14 @@
package com.example.testapp.data.api.model
import com.example.testapp.data.room.models.User
import kotlinx.serialization.Serializable
@Serializable
data class UserRemote(
val id: Int? = 0,
var email: String = "",
var password: String = ""
)
fun UserRemote.toUser(): User = User(id, email, password)
fun User.toRemote(): UserRemote = UserRemote(id, email, password)

View File

@ -0,0 +1,15 @@
package com.example.testapp.data.api.model
import com.example.testapp.data.room.models.WalletItem
import kotlinx.serialization.Serializable
@Serializable
data class WalletItemRemote(
val id: Int,
val coinId: Int,
val userId: Int,
var count: Float,
)
fun WalletItemRemote.toWalletItem(): WalletItem = WalletItem(id, coinId, userId, count)
fun WalletItem.toRemote(): WalletItemRemote = WalletItemRemote(id!!, coinId, userId, count)

View File

@ -0,0 +1,46 @@
package com.example.testapp.data.api.repository
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.model.toCoin
import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.data.room.repository.offline.OfflineCoinRepository
class CoinRestRepository(
private val service: CryptoDealService,
private val dbCoinRepository: OfflineCoinRepository
) : CoinRepository {
override suspend fun insert(vararg x: Coin) {
TODO("Not yet implemented")
}
override suspend fun update(x: Coin) {
TODO("Not yet implemented")
}
override suspend fun delete(x: Coin) {
TODO("Not yet implemented")
}
override suspend fun getById(id: Int): Coin {
TODO("Not yet implemented")
}
override suspend fun getAll(): List<Coin> {
val exists = dbCoinRepository.getAll().associateBy { it.id }.toMutableMap()
service.getCoins()
.map { it.toCoin() }
.forEach { item ->
val existUser = exists[item.id]
if (existUser == null) {
dbCoinRepository.insert(item)
} else if (existUser != item) {
dbCoinRepository.update(item)
}
exists[item.id] = item
}
return exists.map { it.value }.sortedBy { it.id }
}
}

View File

@ -0,0 +1,109 @@
package com.example.testapp.data.api.repository
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.mediator.DealRemoteMediator
import com.example.testapp.data.api.model.toDeal
import com.example.testapp.data.api.model.toRemote
import com.example.testapp.data.room.AppContainer
import com.example.testapp.data.room.database.CryptoDealDb
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.repository.basic.DealRepository
import com.example.testapp.data.room.repository.offline.OfflineDealRepository
import com.example.testapp.data.room.repository.offline.OfflineRemoteKeyRepository
import kotlinx.coroutines.flow.Flow
class DealRestRepository(
private val service: CryptoDealService,
private val dbDealRepository: OfflineDealRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: CryptoDealDb
) : DealRepository {
override suspend fun getUserDeals(id: Int): List<Deal> {
val exists = dbDealRepository.getAll().associateBy { it.id }.toMutableMap()
service.getDeals()
.map { it.toDeal() }
.forEach { item ->
val existUser = exists[item.id]
if (existUser == null) {
dbDealRepository.insert(item)
} else if (existUser != item) {
dbDealRepository.update(item)
}
exists[item.id] = item
}
return exists.map { it.value }.sortedBy { it.id }
}
override suspend fun completeDeal(deal: Deal, sellerId: Int, buyerId: Int): Boolean {
return service.completeDeal(deal.id!!, sellerId, buyerId)
}
override suspend fun clearData() {
TODO("Not yet implemented")
}
override fun pagingData(): Flow<PagingData<Deal>> {
val pagingSourceFactory = { dbDealRepository.getAllPagingData() }
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = DealRemoteMediator(
service,
dbDealRepository,
dbRemoteKeyRepository,
database
),
pagingSourceFactory = pagingSourceFactory
).flow
}
override fun getAllPagingData(): PagingSource<Int, Deal> {
TODO("Not yet implemented")
}
override suspend fun insert(vararg x: Deal) {
x.forEach {y -> service.insert(y.toRemote()) }
}
override suspend fun update(x: Deal) {
x.id?.let { service.update(it, x.toRemote()) }
}
override suspend fun delete(x: Deal) {
x.id?.let { service.deleteDeal(it) }
}
override suspend fun getById(id: Int): Deal {
return service.getDealById(id).toDeal()
}
override suspend fun getAll(): List<Deal> {
val exists = dbDealRepository.getAll().associateBy { it.id }.toMutableMap()
service.getDeals()
.map { it.toDeal() }
.forEach { item ->
val existUser = exists[item.id]
if (existUser == null) {
dbDealRepository.insert(item)
} else if (existUser != item) {
dbDealRepository.update(item)
}
exists[item.id] = item
}
return exists.map { it.value }.sortedBy { it.id }
}
}

View File

@ -0,0 +1,99 @@
package com.example.testapp.data.api.repository
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.model.toDeal
import com.example.testapp.data.api.model.toRemote
import com.example.testapp.data.api.model.toUser
import com.example.testapp.data.api.model.toWalletItem
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.models.User
import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.data.room.repository.basic.DealRepository
import com.example.testapp.data.room.repository.basic.UserRepository
import com.example.testapp.data.room.repository.basic.WalletItemRepository
class UserRestRepository(
private val service: CryptoDealService,
private val dbUserRepository: UserRepository,
private val dbDealRepository: DealRepository,
private val dbWalletItemRepository: WalletItemRepository
) : UserRepository {
override suspend fun getUserWallet(id: Int): List<WalletItem> {
val existArticles = dbUserRepository.getUserWallet(id)
.associateBy { it.userId * 10 + it.coinId }.toMutableMap()
service.getUserWallet(id)
.map { it.toWalletItem() }
.forEach { walletItem ->
val pseudoId = walletItem.userId * 10 + walletItem.coinId
if (walletItem.userId == id) {
val existArt = existArticles[pseudoId]
if (existArt == null) {
dbWalletItemRepository.insert(walletItem)
} else if (existArt != walletItem) {
dbWalletItemRepository.update(walletItem)
}
existArticles[pseudoId] = walletItem
}
}
return existArticles.map { it.value }.sortedBy { it.count }
}
override suspend fun getUserDeals(id: Int): List<Deal> {
val existArticles = dbUserRepository.getUserDeals(id)
.associateBy { it.id }.toMutableMap()
service.getUserDeal(id)
.map { it.toDeal() }
.forEach { deal ->
if (deal.buyerId == id) {
val existArt = existArticles[deal.id]
if (existArt == null) {
dbDealRepository.insert(deal)
} else if (existArt != deal) {
dbDealRepository.update(deal)
}
existArticles[deal.id] = deal
}
}
return existArticles.map { it.value }.sortedBy { it.id }
}
override suspend fun insert(vararg x: User) {
x.forEach { user ->
service.insert(user.toRemote())
}
}
override suspend fun update(x: User) {
x.id?.let { service.update(it, x.toRemote()) }
}
override suspend fun delete(x: User) {
x.id?.let { service.deleteUser(it) }
}
override suspend fun getById(id: Int): User {
return service.getUserById(id).toUser()
}
override suspend fun getAll(): List<User> {
val existUsers = dbUserRepository.getAll().associateBy { it.id }.toMutableMap()
service.getUsers()
.map { it.toUser() }
.forEach { user ->
val existUser = existUsers[user.id]
if (existUser == null) {
dbUserRepository.insert(user)
} else if (existUser != user) {
dbUserRepository.update(user)
}
existUsers[user.id] = user
}
return existUsers.map { it.value }.sortedBy { it.id }
}
}

View File

@ -0,0 +1,90 @@
package com.example.testapp.data.api.repository
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.mediator.WalletItemRemoteMediator
import com.example.testapp.data.api.model.toRemote
import com.example.testapp.data.api.model.toWalletItem
import com.example.testapp.data.room.AppContainer
import com.example.testapp.data.room.database.CryptoDealDb
import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.data.room.repository.basic.WalletItemRepository
import com.example.testapp.data.room.repository.offline.OfflineRemoteKeyRepository
import com.example.testapp.data.room.repository.offline.OfflineWalletItemRepository
import kotlinx.coroutines.flow.Flow
class WalletItemRestRepository(
private val service: CryptoDealService,
private val dbWalletItemRepository: OfflineWalletItemRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: CryptoDealDb
) : WalletItemRepository {
override fun getUserWallet(id: Int): List<WalletItem> {
return dbWalletItemRepository.getUserWallet(id)
}
override fun pagingData(id: Int): Flow<PagingData<WalletItem>> {
val pagingSourceFactory = { dbWalletItemRepository.getWalletItemsPaging(id) }
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = WalletItemRemoteMediator(
service,
dbWalletItemRepository,
dbRemoteKeyRepository,
database
),
pagingSourceFactory = pagingSourceFactory
).flow
}
override fun getWalletItemsPaging(id: Int): PagingSource<Int, WalletItem> {
TODO("Not yet implemented")
}
override suspend fun clearData() {
TODO("Not yet implemented")
}
override suspend fun insert(vararg x: WalletItem) {
x.forEach {y -> service.insert(y.toRemote()) }
}
override suspend fun update(x: WalletItem) {
service.update(x.id!!, x.toRemote())
}
override suspend fun delete(x: WalletItem) {
x.id.let { service.deleteWalletItem(it!!) }
}
override suspend fun getById(id: Int): WalletItem {
TODO("Not yet implemented")
}
override suspend fun getAll(): List<WalletItem> {
val exists = dbWalletItemRepository.getAll().associateBy { it.id }.toMutableMap()
service.getWalletItems()
.map { it.toWalletItem() }
.forEach { item ->
val existUser = exists[item.id]
if (existUser == null) {
dbWalletItemRepository.insert(item)
} else if (existUser != item) {
dbWalletItemRepository.update(item)
}
exists[item.id] = item
}
return exists.map { it.value }.sortedBy { it.id }
}
}

View File

@ -0,0 +1,85 @@
package com.example.testapp.data.room
import android.content.Context
import com.example.testapp.data.api.CryptoDealService
import com.example.testapp.data.api.repository.CoinRestRepository
import com.example.testapp.data.api.repository.DealRestRepository
import com.example.testapp.data.api.repository.UserRestRepository
import com.example.testapp.data.api.repository.WalletItemRestRepository
import com.example.testapp.data.room.database.CryptoDealDb
import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.data.room.repository.basic.DealRepository
import com.example.testapp.data.room.repository.basic.UserRepository
import com.example.testapp.data.room.repository.basic.WalletItemRepository
import com.example.testapp.data.room.repository.offline.OfflineCoinRepository
import com.example.testapp.data.room.repository.offline.OfflineDealRepository
import com.example.testapp.data.room.repository.offline.OfflineRemoteKeyRepository
import com.example.testapp.data.room.repository.offline.OfflineUserRepository
import com.example.testapp.data.room.repository.offline.OfflineWalletItemRepository
interface AppContainer {
val userRepository: UserRepository
val dealRepository: DealRepository
val coinRepository: CoinRepository
val walletItemRepository: WalletItemRepository
val coinRestRepository: CoinRestRepository
val dealRestRepository: DealRestRepository
val userRestRepository: UserRestRepository
val walletItemRestRepository: WalletItemRestRepository
companion object {
const val TIMEOUT = 5000L
const val LIMIT = 10
}
}
class AppDataContainer(
private val context: Context
) : AppContainer {
private val remoteKeyRepository: OfflineRemoteKeyRepository by lazy {
OfflineRemoteKeyRepository(CryptoDealDb.getInstance(context).remoteKeysDao())
}
override val userRepository: UserRepository by lazy {
OfflineUserRepository(CryptoDealDb.getInstance(context).userDao())
}
override val dealRepository: DealRepository by lazy {
OfflineDealRepository(CryptoDealDb.getInstance(context).dealDao())
}
override val coinRepository: CoinRepository by lazy {
OfflineCoinRepository(CryptoDealDb.getInstance(context).coinDao())
}
override val walletItemRepository: WalletItemRepository by lazy {
OfflineWalletItemRepository(CryptoDealDb.getInstance(context).walletItemDao())
}
override val userRestRepository: UserRestRepository by lazy {
UserRestRepository(
CryptoDealService.getInstance(),
userRepository as OfflineUserRepository,
dealRepository as OfflineDealRepository,
walletItemRepository
)
}
override val coinRestRepository: CoinRestRepository by lazy {
CoinRestRepository(
CryptoDealService.getInstance(),
coinRepository as OfflineCoinRepository
)
}
override val dealRestRepository: DealRestRepository by lazy {
DealRestRepository(
CryptoDealService.getInstance(),
dealRepository as OfflineDealRepository,
remoteKeyRepository,
CryptoDealDb.getInstance(context)
)
}
override val walletItemRestRepository: WalletItemRestRepository by lazy {
WalletItemRestRepository(
CryptoDealService.getInstance(),
walletItemRepository as OfflineWalletItemRepository,
remoteKeyRepository,
CryptoDealDb.getInstance(context)
)
}
}

View File

@ -0,0 +1,11 @@
package com.example.testapp.data.room.dao
import androidx.room.Dao
import androidx.room.Query
import com.example.testapp.data.room.models.Coin
@Dao
interface CoinDao : IDao<Coin> {
@Query("select * from coin")
fun getAll(): List<Coin>
}

View File

@ -1,9 +1,9 @@
package com.example.testapp.room.dao package com.example.testapp.data.room.dao
import androidx.paging.PagingSource
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Deal
import com.example.testapp.room.models.User
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
@ -19,4 +19,13 @@ interface DealDao : IDao<Deal> {
@Query("select * from deal where deal.buyerId = :idUser OR deal.sellerId = :idUser") @Query("select * from deal where deal.buyerId = :idUser OR deal.sellerId = :idUser")
fun getUserDeals(idUser: Int): Flow<List<Deal>> fun getUserDeals(idUser: Int): Flow<List<Deal>>
@Query("SELECT * FROM deal WHERE deal.buyerId = :idUser AND deal.date IS NULL OR deal.sellerId = :idUser")
fun getUserDealsPaging(idUser: Int): PagingSource<Int, Deal>
@Query("SELECT * FROM deal ORDER BY id ASC")
fun getDeals(): PagingSource<Int, Deal>
@Query("DELETE FROM deal")
suspend fun deleteAll()
} }

View File

@ -1,4 +1,4 @@
package com.example.testapp.room.dao package com.example.testapp.data.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
@ -8,7 +8,7 @@ import androidx.room.Update
@Dao @Dao
interface IDao<T> { interface IDao<T> {
@Insert @Insert
suspend fun insert(obj: T) suspend fun insert(vararg obj: T)
@Update @Update
suspend fun update(obj: T) suspend fun update(obj: T)

View File

@ -0,0 +1,20 @@
package com.example.testapp.data.room.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.testapp.data.room.models.RemoteKeyType
import com.example.testapp.data.room.models.RemoteKeys
@Dao
interface RemoteKeysDao: IDao<RemoteKeys> {
@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,23 +1,22 @@
package com.example.testapp.room.dao package com.example.testapp.data.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Deal
import com.example.testapp.room.models.User import com.example.testapp.data.room.models.User
import com.example.testapp.room.models.WalletItem import com.example.testapp.data.room.models.WalletItem
import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface UserDao : IDao<User> { interface UserDao : IDao<User> {
@Query("select * from user") @Query("select * from user")
fun getAll(): Flow<List<User>> fun getAll(): List<User>
@Query("select * from user where user.id = :idUser") @Query("select * from user where user.id = :idUser")
fun getUserById(idUser: Int): User fun getUserById(idUser: Int): User
@Query("select * from walletitem where walletitem.userId = :idUser") @Query("select * from walletitem where walletitem.userId = :idUser")
fun getUserWallet(idUser: Int): Flow<List<WalletItem>> fun getUserWallet(idUser: Int): List<WalletItem>
@Query("select * from deal where deal.buyerId = :idUser OR deal.sellerId = :idUser") @Query("select * from deal where deal.buyerId = :idUser OR deal.sellerId = :idUser")
fun getUserDeals(idUser: Int): Flow<List<Deal>> fun getUserDeals(idUser: Int): List<Deal>
} }

View File

@ -0,0 +1,24 @@
package com.example.testapp.data.room.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Query
import com.example.testapp.data.room.models.WalletItem
@Dao
interface WalletItemDao : IDao<WalletItem> {
@Query("select * from walletitem")
fun getAll(): List<WalletItem>
@Query("select * from walletitem where walletitem.userId = :id ORDER BY walletitem.coinId DESC LIMIT :limit OFFSET :offset")
fun getAll(limit: Int, offset: Int, id: Int): List<WalletItem>
@Query("select * from walletitem where walletitem.userId = :id")
fun getUserWallet(id: Int): List<WalletItem>
@Query("SELECT * FROM walletitem where walletitem.userId = :id ORDER BY walletitem.coinId ASC")
fun getWallet(id: Int): PagingSource<Int, WalletItem>
@Query("DELETE FROM walletitem")
suspend fun deleteAll()
}

View File

@ -1,18 +1,22 @@
package com.example.testapp.room.database package com.example.testapp.data.room.database
import android.content.Context import android.content.Context
import androidx.room.Database import androidx.room.Database
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase import com.example.testapp.data.room.dao.CoinDao
import com.example.testapp.room.dao.* import com.example.testapp.data.room.dao.DealDao
import com.example.testapp.room.models.* import com.example.testapp.data.room.dao.RemoteKeysDao
import kotlinx.coroutines.CoroutineScope import com.example.testapp.data.room.dao.UserDao
import kotlinx.coroutines.Dispatchers import com.example.testapp.data.room.dao.WalletItemDao
import kotlinx.coroutines.launch import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.models.RemoteKeys
import com.example.testapp.data.room.models.User
import com.example.testapp.data.room.models.WalletItem
@Database( @Database(
entities = [User::class, Deal::class, Coin::class, WalletItem::class], entities = [User::class, Deal::class, Coin::class, WalletItem::class, RemoteKeys::class],
version = 2, version = 2,
exportSchema = false) exportSchema = false)
abstract class CryptoDealDb: RoomDatabase() { abstract class CryptoDealDb: RoomDatabase() {
@ -20,9 +24,10 @@ abstract class CryptoDealDb: RoomDatabase() {
abstract fun coinDao(): CoinDao; abstract fun coinDao(): CoinDao;
abstract fun dealDao(): DealDao; abstract fun dealDao(): DealDao;
abstract fun walletItemDao(): WalletItemDao; abstract fun walletItemDao(): WalletItemDao;
abstract fun remoteKeysDao(): RemoteKeysDao;
companion object { companion object {
private const val DB_NAME: String = "crypto-deal7" private const val DB_NAME: String = "crypto-deal13"
@Volatile @Volatile
private var INSTANCE: CryptoDealDb? = null private var INSTANCE: CryptoDealDb? = null
@ -52,25 +57,25 @@ abstract class CryptoDealDb: RoomDatabase() {
coinDao.insert(c6) coinDao.insert(c6)
coinDao.insert(c7) coinDao.insert(c7)
val walletItemDao = database.walletItemDao(); // val walletItemDao = database.walletItemDao();
val wi1 = WalletItem(0, 0, 0.5f); // val wi1 = WalletItem(0, 0, 0.5f);
val wi2 = WalletItem(1, 0, 0.6f); // val wi2 = WalletItem(1, 0, 0.6f);
val wi3 = WalletItem(3, 0, 0.7f); // val wi3 = WalletItem(3, 0, 0.7f);
val wi4 = WalletItem(0, 1, 1000f); // val wi4 = WalletItem(0, 1, 1000f);
val wi5 = WalletItem(3, 1, 10f); // val wi5 = WalletItem(3, 1, 10f);
val wi6 = WalletItem(2, 1, 1f); // val wi6 = WalletItem(2, 1, 1f);
val wi7 = WalletItem(4, 0, 1.1f); // val wi7 = WalletItem(4, 0, 1.1f);
val wi8 = WalletItem(5, 0, 1.1f); // val wi8 = WalletItem(5, 0, 1.1f);
val wi9 = WalletItem(6, 0, 1.1f); // val wi9 = WalletItem(6, 0, 1.1f);
walletItemDao.insert(wi1); // walletItemDao.insert(wi1);
walletItemDao.insert(wi2); // walletItemDao.insert(wi2);
walletItemDao.insert(wi3); // walletItemDao.insert(wi3);
walletItemDao.insert(wi4); // walletItemDao.insert(wi4);
walletItemDao.insert(wi5); // walletItemDao.insert(wi5);
walletItemDao.insert(wi6); // walletItemDao.insert(wi6);
walletItemDao.insert(wi7); // walletItemDao.insert(wi7);
walletItemDao.insert(wi8); // walletItemDao.insert(wi8);
walletItemDao.insert(wi9); // walletItemDao.insert(wi9);
val dealDao = database.dealDao(); val dealDao = database.dealDao();
val d1 = Deal(0, null, 0, 2, 0, 0.1f, 0.2f, "Buy", null, "TEST1") val d1 = Deal(0, null, 0, 2, 0, 0.1f, 0.2f, "Buy", null, "TEST1")
@ -91,14 +96,14 @@ abstract class CryptoDealDb: RoomDatabase() {
CryptoDealDb::class.java, CryptoDealDb::class.java,
DB_NAME DB_NAME
) )
.addCallback(object : Callback() { // .addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) { // override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db) // super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch { // CoroutineScope(Dispatchers.IO).launch {
populateDatabase() // populateDatabase()
} // }
} // }
}) // })
.allowMainThreadQueries() .allowMainThreadQueries()
.build() .build()
.also { INSTANCE = it } .also { INSTANCE = it }

View File

@ -1,4 +1,4 @@
package com.example.testapp.room.models package com.example.testapp.data.room.models
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

View File

@ -1,8 +1,7 @@
package com.example.testapp.room.models package com.example.testapp.data.room.models
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.time.LocalDateTime
@Entity @Entity
class Deal ( class Deal (
@ -18,5 +17,11 @@ class Deal (
var date: Long?, var date: Long?,
val tip: String, val tip: String,
) { ) {
override fun equals(other: Any?): Boolean {
return (other as Deal).id == this.id
}
override fun hashCode(): Int {
return id ?: -1
}
} }

View File

@ -0,0 +1,26 @@
package com.example.testapp.data.room.models
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
DEAL(Deal::class.simpleName ?: "Deal"),
WALLETITEM(WalletItem::class.simpleName ?: "WalletItem");
@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

@ -1,4 +1,4 @@
package com.example.testapp.room.models package com.example.testapp.data.room.models
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

View File

@ -1,17 +1,29 @@
package com.example.testapp.room.models package com.example.testapp.data.room.models
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
@Entity( @Entity(
primaryKeys = ["coinId", "userId"],
foreignKeys = [ foreignKeys = [
ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["userId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE), ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["userId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE),
ForeignKey(entity = Coin::class, parentColumns = ["id"], childColumns = ["coinId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE) ForeignKey(entity = Coin::class, parentColumns = ["id"], childColumns = ["coinId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE)
] ],
indices = [Index(value = ["coinId", "userId"])]
) )
class WalletItem ( class WalletItem (
@PrimaryKey(autoGenerate = true) val id: Int?,
val coinId: Int, val coinId: Int,
val userId: Int, val userId: Int,
var count: Float var count: Float,
) ) {
override fun equals(other: Any?): Boolean {
other as WalletItem
return other.coinId == this.coinId && other.userId == this.userId
}
override fun hashCode(): Int {
return id!!
}
}

View File

@ -1,10 +1,9 @@
package com.example.testapp.room.pagination package com.example.testapp.data.room.pagination
import android.util.Log
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState import androidx.paging.PagingState
import com.example.testapp.room.dao.DealDao import com.example.testapp.data.room.dao.DealDao
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Deal
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
class DealPagination( class DealPagination(

View File

@ -1,11 +1,10 @@
package com.example.testapp.room.pagination package com.example.testapp.data.room.pagination
import android.util.Log import android.util.Log
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState import androidx.paging.PagingState
import com.example.testapp.room.dao.WalletItemDao import com.example.testapp.data.room.dao.WalletItemDao
import com.example.testapp.room.models.WalletItem import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
class WalletPagination( class WalletPagination(

View File

@ -0,0 +1,6 @@
package com.example.testapp.data.room.repository.basic
import com.example.testapp.data.room.models.Coin
interface CoinRepository : IRepository<Coin> {
}

View File

@ -0,0 +1,14 @@
package com.example.testapp.data.room.repository.basic
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.testapp.data.room.models.Deal
import kotlinx.coroutines.flow.Flow
interface DealRepository : IRepository<Deal> {
suspend fun getUserDeals(id: Int): List<Deal>
suspend fun completeDeal(deal: Deal, sellerId: Int, buyerId: Int): Boolean
suspend fun clearData()
fun pagingData(): Flow<PagingData<Deal>>
fun getAllPagingData(): PagingSource<Int, Deal>
}

View File

@ -0,0 +1,9 @@
package com.example.testapp.data.room.repository.basic
interface IRepository<T> {
suspend fun insert(vararg x: T)
suspend fun update(x: T)
suspend fun delete(x: T)
suspend fun getById(id: Int): T
suspend fun getAll(): List<T>
}

View File

@ -0,0 +1,10 @@
package com.example.testapp.data.room.repository.basic
import com.example.testapp.data.room.models.RemoteKeyType
import com.example.testapp.data.room.models.RemoteKeys
interface RemoteKeyRepository {
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
suspend fun deleteRemoteKey(type: RemoteKeyType)
}

View File

@ -0,0 +1,10 @@
package com.example.testapp.data.room.repository.basic
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.models.User
import com.example.testapp.data.room.models.WalletItem
interface UserRepository : IRepository<User> {
suspend fun getUserWallet(id: Int): List<WalletItem>
suspend fun getUserDeals(id: Int): List<Deal>
}

View File

@ -0,0 +1,13 @@
package com.example.testapp.data.room.repository.basic
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.testapp.data.room.models.WalletItem
import kotlinx.coroutines.flow.Flow
interface WalletItemRepository : IRepository<WalletItem> {
fun getUserWallet(id: Int): List<WalletItem>
fun pagingData(id: Int): Flow<PagingData<WalletItem>>
fun getWalletItemsPaging(id: Int): PagingSource<Int, WalletItem>
suspend fun clearData()
}

View File

@ -0,0 +1,12 @@
package com.example.testapp.data.room.repository.offline
import com.example.testapp.data.room.dao.CoinDao
import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.repository.basic.CoinRepository
class OfflineCoinRepository(
private val coinDao: CoinDao
) : OfflineRepository<Coin>(coinDao), CoinRepository {
override suspend fun getAll(): List<Coin> = coinDao.getAll()
override suspend fun getById(id: Int): Coin = throw NotImplementedError()
}

View File

@ -0,0 +1,33 @@
package com.example.testapp.data.room.repository.offline
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.testapp.data.room.dao.DealDao
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.pagination.DealPagination
import com.example.testapp.data.room.repository.basic.DealRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
class OfflineDealRepository(
private val dealDao: DealDao
) : OfflineRepository<Deal>(dealDao), DealRepository {
override suspend fun getAll(): List<Deal> = dealDao.getAll().first()
override suspend fun getById(id: Int): Deal = dealDao.getById(id);
override suspend fun getUserDeals(id: Int): List<Deal> = dealDao.getUserDeals(id).first()
override suspend fun completeDeal(deal: Deal, sellerId: Int, buyerId: Int): Boolean {
return true;
}
override suspend fun clearData() = dealDao.deleteAll()
override fun pagingData(): Flow<PagingData<Deal>> = Pager(config = PagingConfig(
pageSize = 4, jumpThreshold = 4, initialLoadSize = 4
), pagingSourceFactory = { DealPagination(dealDao) }, initialKey = 1).flow
override fun getAllPagingData() = dealDao.getDeals()
suspend fun insert(list: List<Deal>) = dealDao.insert(*list.toTypedArray())
}

View File

@ -0,0 +1,17 @@
package com.example.testapp.data.room.repository.offline
import com.example.testapp.data.room.dao.RemoteKeysDao
import com.example.testapp.data.room.models.RemoteKeyType
import com.example.testapp.data.room.models.RemoteKeys
import com.example.testapp.data.room.repository.basic.RemoteKeyRepository
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

@ -0,0 +1,12 @@
package com.example.testapp.data.room.repository.offline
import com.example.testapp.data.room.dao.IDao
import com.example.testapp.data.room.repository.basic.IRepository
abstract class OfflineRepository<T> (
private val dao: IDao<T>
) : IRepository<T> {
override suspend fun insert(vararg x: T) = dao.insert(*x)
override suspend fun update(x: T) = dao.update(x)
override suspend fun delete(x: T) = dao.delete(x)
}

View File

@ -0,0 +1,16 @@
package com.example.testapp.data.room.repository.offline
import com.example.testapp.data.room.dao.UserDao
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.models.User
import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.data.room.repository.basic.UserRepository
class OfflineUserRepository(
private val userDao: UserDao
) : OfflineRepository<User>(userDao), UserRepository {
override suspend fun getAll(): List<User> = userDao.getAll()
override suspend fun getById(id: Int): User = userDao.getUserById(id)
override suspend fun getUserWallet(id: Int): List<WalletItem> = userDao.getUserWallet(id)
override suspend fun getUserDeals(id: Int): List<Deal> = userDao.getUserDeals(id)
}

View File

@ -0,0 +1,27 @@
package com.example.testapp.data.room.repository.offline
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.testapp.data.room.dao.WalletItemDao
import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.data.room.pagination.WalletPagination
import com.example.testapp.data.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.flow.Flow
class OfflineWalletItemRepository(
private val walletItemDao: WalletItemDao
) : OfflineRepository<WalletItem>(walletItemDao), WalletItemRepository {
override fun getUserWallet(id: Int): List<WalletItem> = walletItemDao.getUserWallet(id)
override suspend fun getAll(): List<WalletItem> = walletItemDao.getAll()
override suspend fun getById(id: Int): WalletItem = throw NotImplementedError()
override fun pagingData(id: Int): Flow<PagingData<WalletItem>> = Pager(config = PagingConfig(
pageSize = 10, jumpThreshold = 10, initialLoadSize = 10
), pagingSourceFactory = { WalletPagination(walletItemDao, id) }, initialKey = 1).flow
override fun getWalletItemsPaging(id: Int): PagingSource<Int, WalletItem> = walletItemDao.getWallet(id)
override suspend fun clearData() = walletItemDao.deleteAll()
suspend fun insert(list: List<WalletItem>) = walletItemDao.insert(*list.toTypedArray())
}

View File

@ -32,8 +32,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.testapp.room.models.Coin import com.example.testapp.data.room.models.Coin
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Deal
@Composable @Composable
fun DealItem(modifier: Modifier = Modifier, deal: Deal, coins: List<Coin>) { fun DealItem(modifier: Modifier = Modifier, deal: Deal, coins: List<Coin>) {

View File

@ -18,8 +18,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@ -27,7 +25,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.testapp.room.models.Coin import com.example.testapp.data.room.models.Coin
@Composable @Composable
fun ListItem(modifier: Modifier = Modifier, coin : Coin, count: Float) { fun ListItem(modifier: Modifier = Modifier, coin : Coin, count: Float) {

View File

@ -1,7 +1,6 @@
package com.example.pmulabs.designElem package com.example.pmulabs.designElem
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -11,7 +10,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidth import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -21,7 +19,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.toUpperCase
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
@ -30,7 +27,6 @@ import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import com.example.testapp.navigate.BottomBarScreen import com.example.testapp.navigate.BottomBarScreen
import java.util.Locale
@Composable @Composable
fun NavBar(navController: NavHostController){ fun NavBar(navController: NavHostController){
@ -84,7 +80,7 @@ fun AddItem(
.clickable(onClick = { .clickable(onClick = {
navController.navigate(screen.route) { navController.navigate(screen.route) {
popUpTo(navController.graph.findStartDestination().id) popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = false launchSingleTop = true
} }
}) })
.clip(shape = RoundedCornerShape(10.dp)) .clip(shape = RoundedCornerShape(10.dp))

View File

@ -1,24 +0,0 @@
package com.example.testapp.designElem
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
val argument = mutableStateOf<String?>(null)
val argument_edit = mutableStateOf<Any?>(null)
val argument_add_f = mutableStateOf<Any?>(null)
val argument_add_c = mutableStateOf<Any?>(null)
fun setArgumentAdd(arg1: Any, arg2: Any) {
argument_add_f.value = arg1
argument_add_c.value = arg2
}
fun setArgumentEdit(arg: Any?) {
argument_edit.value = arg
}
fun setArgument(arg: String) {
argument.value = arg
}
}

View File

@ -6,18 +6,20 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.navigate.BottomBarScreen import com.example.testapp.navigate.BottomBarScreen
import com.example.testapp.screensMobile.AccountPage import com.example.testapp.screensMobile.AccountPage
import com.example.testapp.screensMobile.CreateDeal import com.example.testapp.screensMobile.CreateDeal
import com.example.testapp.screensMobile.DealList import com.example.testapp.screensMobile.DealList
import com.example.testapp.screensMobile.History import com.example.testapp.screensMobile.History
import com.example.testapp.screensMobile.ReportScreen
import com.example.testapp.screensMobile.Wallet import com.example.testapp.screensMobile.Wallet
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel import com.example.testapp.viewModels.DealCreateViewModel
import com.example.testapp.viewModels.DealListViewModel import com.example.testapp.viewModels.DealListViewModel
import com.example.testapp.viewModels.HistoryViewModel import com.example.testapp.viewModels.HistoryViewModel
import com.example.testapp.viewModels.ReportViewModel
import com.example.testapp.viewModels.SharedViewModel
import com.example.testapp.viewModels.WalletViewModel import com.example.testapp.viewModels.WalletViewModel
@RequiresApi(34) @RequiresApi(34)
@ -29,6 +31,7 @@ fun HomeNavGraph(
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory), dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory),
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory), historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory),
walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory), walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory),
reportViewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory),
sharedViewModel: SharedViewModel sharedViewModel: SharedViewModel
) { ) {
NavHost( NavHost(
@ -72,5 +75,12 @@ fun HomeNavGraph(
historyViewModel = historyViewModel historyViewModel = historyViewModel
) )
} }
composable(route = BottomBarScreen.Report.route) {
ReportScreen(
navController = navController,
currentUserViewModel = currentUserViewModel,
reportViewModel = reportViewModel
)
}
} }
} }

View File

@ -8,7 +8,6 @@ import androidx.navigation.NavType
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.screensMobile.LoadScreen import com.example.testapp.screensMobile.LoadScreen
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
@ -17,6 +16,8 @@ import com.example.testapp.viewModels.DealListViewModel
import com.example.testapp.viewModels.EntryScreenViewModel import com.example.testapp.viewModels.EntryScreenViewModel
import com.example.testapp.viewModels.HistoryViewModel import com.example.testapp.viewModels.HistoryViewModel
import com.example.testapp.viewModels.RegistrationScreenViewModel import com.example.testapp.viewModels.RegistrationScreenViewModel
import com.example.testapp.viewModels.ReportViewModel
import com.example.testapp.viewModels.SharedViewModel
import com.example.testapp.viewModels.WalletViewModel import com.example.testapp.viewModels.WalletViewModel
const val USERID_ARGUMENT = "userId" const val USERID_ARGUMENT = "userId"
@ -32,6 +33,7 @@ fun RootNavigationGraph(
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory), historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory),
registrationScreenViewModel: RegistrationScreenViewModel = viewModel(factory = AppViewModelProvider.Factory), registrationScreenViewModel: RegistrationScreenViewModel = viewModel(factory = AppViewModelProvider.Factory),
walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory), walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory),
reportViewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory),
sharedViewModel: SharedViewModel sharedViewModel: SharedViewModel
) { ) {
NavHost( NavHost(
@ -57,7 +59,8 @@ fun RootNavigationGraph(
dealListViewModel = dealListViewModel, dealListViewModel = dealListViewModel,
historyViewModel = historyViewModel, historyViewModel = historyViewModel,
walletViewModel = walletViewModel, walletViewModel = walletViewModel,
sharedViewModel = sharedViewModel sharedViewModel = sharedViewModel,
reportViewModel = reportViewModel
) )
} }
} }

View File

@ -20,6 +20,10 @@ sealed class BottomBarScreen(
route = "HISTORY", route = "HISTORY",
title = "History" title = "History"
) )
object Report: BottomBarScreen(
route = "REPORT",
title = "Report"
)
object CDEAL: BottomBarScreen( object CDEAL: BottomBarScreen(
route = "CDEAL", route = "CDEAL",
title = "CDEAL" title = "CDEAL"

View File

@ -1,40 +0,0 @@
package com.example.testapp.room
import android.content.Context
import com.example.testapp.room.database.CryptoDealDb
import com.example.testapp.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.DealRepository
import com.example.testapp.room.repository.basic.UserRepository
import com.example.testapp.room.repository.basic.WalletItemRepository
import com.example.testapp.room.repository.offline.OfflineCoinRepository
import com.example.testapp.room.repository.offline.OfflineDealRepository
import com.example.testapp.room.repository.offline.OfflineUserRepository
import com.example.testapp.room.repository.offline.OfflineWalletItemRepository
interface AppContainer {
val userRepository: UserRepository
val dealRepository: DealRepository
val coinRepository: CoinRepository
val walletItemRepository: WalletItemRepository
}
class AppDataContainer(
private val context: Context
) : AppContainer {
companion object {
const val TIMEOUT = 5000L
}
override val userRepository: UserRepository by lazy {
OfflineUserRepository(CryptoDealDb.getInstance(context).userDao())
}
override val dealRepository: DealRepository by lazy {
OfflineDealRepository(CryptoDealDb.getInstance(context).dealDao())
}
override val coinRepository: CoinRepository by lazy {
OfflineCoinRepository(CryptoDealDb.getInstance(context).coinDao())
}
override val walletItemRepository: WalletItemRepository by lazy {
OfflineWalletItemRepository(CryptoDealDb.getInstance(context).walletItemDao())
}
}

View File

@ -1,12 +0,0 @@
package com.example.testapp.room.dao
import androidx.room.Dao
import androidx.room.Query
import com.example.testapp.room.models.Coin
import kotlinx.coroutines.flow.Flow
@Dao
interface CoinDao : IDao<Coin> {
@Query("select * from coin")
fun getAll(): Flow<List<Coin>>
}

View File

@ -1,19 +0,0 @@
package com.example.testapp.room.dao
import androidx.room.Dao
import androidx.room.Query
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import kotlinx.coroutines.flow.Flow
@Dao
interface WalletItemDao : IDao<WalletItem> {
@Query("select * from walletitem")
fun getAll(): Flow<List<WalletItem>>
@Query("select * from walletitem where walletitem.userId = :id ORDER BY walletitem.coinId DESC LIMIT :limit OFFSET :offset")
fun getAll(limit: Int, offset: Int, id: Int): List<WalletItem>
@Query("select * from walletitem where walletitem.userId = :id")
fun getUserWallet(id: Int): Flow<List<WalletItem>>
}

View File

@ -1,6 +0,0 @@
package com.example.testapp.room.repository.basic
import com.example.testapp.room.models.Coin
interface CoinRepository : IRepository<Coin> {
}

View File

@ -1,12 +0,0 @@
package com.example.testapp.room.repository.basic
import androidx.paging.PagingData
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import kotlinx.coroutines.flow.Flow
interface DealRepository : IRepository<Deal> {
fun getUserDeals(id: Int): Flow<List<Deal>>
fun completeDeal(deal: Deal, sellerId: Int, buyerId: Int): Boolean
fun pagingData(): Flow<PagingData<Deal>>
}

View File

@ -1,11 +0,0 @@
package com.example.testapp.room.repository.basic
import kotlinx.coroutines.flow.Flow
interface IRepository<T> {
suspend fun insert(x: T)
suspend fun update(x: T)
suspend fun delete(x: T)
fun getById(id: Int): T
fun getAll(): Flow<List<T>>
}

View File

@ -1,11 +0,0 @@
package com.example.testapp.room.repository.basic
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.User
import com.example.testapp.room.models.WalletItem
import kotlinx.coroutines.flow.Flow
interface UserRepository : IRepository<User> {
fun getUserWallet(id: Int): Flow<List<WalletItem>>
fun getUserDeals(id: Int): Flow<List<Deal>>
}

View File

@ -1,13 +0,0 @@
package com.example.testapp.room.repository.basic
import androidx.lifecycle.LiveData
import androidx.paging.PagingData
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import kotlinx.coroutines.flow.Flow
interface WalletItemRepository : IRepository<WalletItem> {
fun getUserWallet(id: Int): Flow<List<WalletItem>>
fun pagingData(id: Int): Flow<PagingData<WalletItem>>
fun pagingDataTest(id: Int): LiveData<PagingData<WalletItem>>
}

View File

@ -1,20 +0,0 @@
package com.example.testapp.room.repository.offline
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.testapp.room.dao.CoinDao
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import com.example.testapp.room.pagination.DealPagination
import com.example.testapp.room.pagination.WalletPagination
import com.example.testapp.room.repository.basic.CoinRepository
import kotlinx.coroutines.flow.Flow
class OfflineCoinRepository(
private val coinDao: CoinDao
) : OfflineRepository<Coin>(coinDao), CoinRepository {
override fun getAll(): Flow<List<Coin>> = coinDao.getAll()
override fun getById(id: Int): Coin = throw NotImplementedError()
}

View File

@ -1,28 +0,0 @@
package com.example.testapp.room.repository.offline
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.testapp.room.dao.DealDao
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import com.example.testapp.room.pagination.DealPagination
import com.example.testapp.room.pagination.WalletPagination
import com.example.testapp.room.repository.basic.DealRepository
import kotlinx.coroutines.flow.Flow
class OfflineDealRepository(
private val dealDao: DealDao
) : OfflineRepository<Deal>(dealDao), DealRepository {
override fun getAll(): Flow<List<Deal>> = dealDao.getAll()
override fun getById(id: Int): Deal = dealDao.getById(id);
override fun getUserDeals(id: Int): Flow<List<Deal>> = dealDao.getUserDeals(id)
override fun completeDeal(deal: Deal, sellerId: Int, buyerId: Int): Boolean {
return true;
}
override fun pagingData(): Flow<PagingData<Deal>> = Pager(config = PagingConfig(
pageSize = 4, jumpThreshold = 4, initialLoadSize = 4
), pagingSourceFactory = { DealPagination(dealDao) }, initialKey = 1).flow
}

View File

@ -1,12 +0,0 @@
package com.example.testapp.room.repository.offline
import com.example.testapp.room.dao.IDao
import com.example.testapp.room.repository.basic.IRepository
abstract class OfflineRepository<T> (
private val dao: IDao<T>
) : IRepository<T> {
override suspend fun insert(x: T) = dao.insert(x)
override suspend fun update(x: T) = dao.update(x)
override suspend fun delete(x: T) = dao.delete(x)
}

View File

@ -1,17 +0,0 @@
package com.example.testapp.room.repository.offline
import com.example.testapp.room.dao.UserDao
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.User
import com.example.testapp.room.models.WalletItem
import com.example.testapp.room.repository.basic.UserRepository
import kotlinx.coroutines.flow.Flow
class OfflineUserRepository(
private val userDao: UserDao
) : OfflineRepository<User>(userDao), UserRepository {
override fun getAll(): Flow<List<User>> = userDao.getAll()
override fun getById(id: Int): User = userDao.getUserById(id)
override fun getUserWallet(id: Int): Flow<List<WalletItem>> = userDao.getUserWallet(id)
override fun getUserDeals(id: Int): Flow<List<Deal>> = userDao.getUserDeals(id)
}

View File

@ -1,29 +0,0 @@
package com.example.testapp.room.repository.offline
import androidx.lifecycle.LiveData
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.liveData
import com.example.testapp.room.dao.WalletItemDao
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import com.example.testapp.room.pagination.WalletPagination
import com.example.testapp.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.flow.Flow
class OfflineWalletItemRepository(
private val walletItemDao: WalletItemDao
) : OfflineRepository<WalletItem>(walletItemDao), WalletItemRepository {
override fun getUserWallet(id: Int): Flow<List<WalletItem>> = walletItemDao.getUserWallet(id)
override fun getAll(): Flow<List<WalletItem>> = walletItemDao.getAll()
override fun getById(id: Int): WalletItem = throw NotImplementedError()
override fun pagingData(id: Int): Flow<PagingData<WalletItem>> = Pager(config = PagingConfig(
pageSize = 10, jumpThreshold = 10, initialLoadSize = 10
), pagingSourceFactory = { WalletPagination(walletItemDao, id) }, initialKey = 1).flow
override fun pagingDataTest(id: Int): LiveData<PagingData<WalletItem>> = Pager(config = PagingConfig(
pageSize = 1, jumpThreshold = 1, initialLoadSize = 1
), pagingSourceFactory = { WalletPagination(walletItemDao, id) }, initialKey = 1).liveData
}

View File

@ -1,6 +1,8 @@
package com.example.testapp.screensMobile package com.example.testapp.screensMobile
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -17,17 +19,18 @@ import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Fingerprint
import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@ -36,11 +39,12 @@ import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination import com.example.testapp.R
import com.example.testapp.graphs.AuthScreen import com.example.testapp.navigate.BottomBarScreen
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("CoroutineCreationDuringComposition") @SuppressLint("CoroutineCreationDuringComposition")
@Composable @Composable
fun AccountPage( fun AccountPage(
@ -122,8 +126,7 @@ fun AccountPage(
y = 204.dp y = 204.dp
) )
) { ) {
Property1Switch(modifier = Modifier.padding(vertical = 5.dp)) Property1Arrow(modifier = Modifier.padding(vertical = 5.dp), navController)
Property1Arrow(modifier = Modifier.padding(vertical = 5.dp))
} }
Property1Clear(navController = navController) Property1Clear(navController = navController)
Property1( Property1(
@ -137,46 +140,6 @@ fun AccountPage(
} }
} }
@Composable
fun Property1Switch(modifier: Modifier = Modifier) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.background(color = Color.White)
.padding(
start = 12.dp,
end = 16.dp,
top = 4.dp,
bottom = 4.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(all = 12.dp)
) {
// Icon(
// painter = painterResource(id = R.drawable.sizem),
// contentDescription = "IconFavorite",
// tint = Color(0xff002033).copy(alpha = 0.35f))
}
Text(
text = "Enable Notifications",
color = Color(0xff0b1f33),
lineHeight = 1.25.em,
style = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp
),
modifier = Modifier
.weight(weight = 1f)
.wrapContentHeight(align = Alignment.CenterVertically)
)
Viewchecked()
}
}
@Composable @Composable
fun Container(modifier: Modifier = Modifier, name: String) { fun Container(modifier: Modifier = Modifier, name: String) {
Column( Column(
@ -231,7 +194,7 @@ fun Viewchecked(modifier: Modifier = Modifier) {
} }
@Composable @Composable
fun Property1Arrow(modifier: Modifier = Modifier) { fun Property1Arrow(modifier: Modifier = Modifier, navController: NavController) {
Row( Row(
horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally), horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@ -243,19 +206,22 @@ fun Property1Arrow(modifier: Modifier = Modifier) {
top = 4.dp, top = 4.dp,
bottom = 4.dp bottom = 4.dp
) )
.clickable {
navController.navigate(route = BottomBarScreen.Report.route)
}
) { ) {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.padding(all = 12.dp) .padding(all = 12.dp)
) { ) {
// Icon( Icon(
// painter = painterResource(id = R.drawable.sizem), Icons.Rounded.Fingerprint,
// contentDescription = "IconFavorite", contentDescription = stringResource(id = R.string.app_name)
// tint = Color(0xff002033).copy(alpha = 0.35f)) )
} }
Text( Text(
text = "Confirm Account", text = "Report",
color = Color(0xff0b1f33), color = Color(0xff0b1f33),
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
@ -275,12 +241,6 @@ fun Property1Clear(modifier: Modifier = Modifier, navController: NavController)
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.clip(shape = RoundedCornerShape(10.dp)) .clip(shape = RoundedCornerShape(10.dp))
.clickable {
navController.navigate(route = AuthScreen.Entry.route) {
popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = true
}
}
.padding( .padding(
start = 16.dp, start = 16.dp,
end = 16.dp, end = 16.dp,

View File

@ -39,16 +39,16 @@ import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.designElem.DropDown import com.example.testapp.designElem.DropDown
import com.example.testapp.designElem.DropDownConfig import com.example.testapp.designElem.DropDownConfig
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.navigate.BottomBarScreen import com.example.testapp.navigate.BottomBarScreen
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel import com.example.testapp.viewModels.DealCreateViewModel
import com.example.testapp.viewModels.SharedViewModel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@ -43,10 +43,10 @@ import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.paging.LoadState import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import com.example.testapp.designElem.SharedViewModel import com.example.testapp.viewModels.SharedViewModel
import com.example.testapp.navigate.BottomBarScreen import com.example.testapp.navigate.BottomBarScreen
import com.example.testapp.room.models.Coin import com.example.testapp.data.room.models.Coin
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Deal
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel import com.example.testapp.viewModels.DealCreateViewModel
@ -98,16 +98,16 @@ fun DealList(
} }
deals.apply { deals.apply {
when{ when{
loadState.refresh is LoadState.Loading -> { // loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator( // item { CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(0.5f), // modifier = Modifier.fillParentMaxSize(0.5f),
color = Color(0xff423a99)) } // color = Color(0xff423a99)) }
} // }
loadState.append is LoadState.Loading -> { // loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator( // item { CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(0.5f), // modifier = Modifier.fillParentMaxSize(0.5f),
color = Color(0xff423a99)) } // color = Color(0xff423a99)) }
} // }
loadState.refresh is LoadState.Error -> { loadState.refresh is LoadState.Error -> {
val err = deals.loadState.refresh as LoadState.Error val err = deals.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) } item { Text(err.error.localizedMessage) }

View File

@ -6,21 +6,19 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -36,8 +34,9 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.example.testapp.room.models.Coin import androidx.paging.compose.collectAsLazyPagingItems
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.models.Deal
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.HistoryViewModel import com.example.testapp.viewModels.HistoryViewModel
@ -55,26 +54,31 @@ fun History(
) { ) {
val user by currentUserViewModel.user.collectAsState() val user by currentUserViewModel.user.collectAsState()
val id = user!!.id val id = user!!.id
historyViewModel.setArgument(id.toString()); historyViewModel.setArgument(id.toString())
val history by historyViewModel.deals.collectAsState() val history = historyViewModel.deals.collectAsLazyPagingItems()
val coins by historyViewModel.coins.collectAsState() val coins by historyViewModel.coins.collectAsState()
Column( LazyColumn(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = PaddingValues(bottom = 70.dp),
modifier = modifier modifier = modifier
.requiredHeight(height = 720.dp)
.background(color = Color(0xfff4f7fb)) .background(color = Color(0xfff4f7fb))
.padding(vertical = 20.dp) .padding(vertical = 20.dp)
.verticalScroll(rememberScrollState()) .fillMaxSize()
) { ) {
PropertyHistory() item {
history.forEach { x -> PropertyHistory()
HistoryCard( }
deal = x, items(count = history.itemCount) {
modifier = Modifier.padding(vertical = 5.dp, horizontal = 5.dp), val item = history[it]
coins = coins if (item != null) {
) HistoryCard(
deal = item,
modifier = Modifier.padding(vertical = 5.dp, horizontal = 5.dp),
coins = coins
)
}
} }
} }
} }

View File

@ -0,0 +1,294 @@
package com.example.testapp.screensMobile
import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.models.Deal
import com.example.testapp.navigate.BottomBarScreen
import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.ReportViewModel
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
@RequiresApi(Build.VERSION_CODES.O)
fun longToDate(value: Long): LocalDateTime {
return LocalDateTime
.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.UTC)
}
@OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("CoroutineCreationDuringComposition", "SimpleDateFormat")
@Composable
fun ReportScreen(
modifier: Modifier = Modifier,
navController: NavController,
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
reportViewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
reportViewModel.clearLists()
val user by currentUserViewModel.user.collectAsState()
val deals by reportViewModel.deals.collectAsState()
val coins by reportViewModel.coins.collectAsState()
val dateStateFrom = rememberDatePickerState()
val showDialogFrom = rememberSaveable { mutableStateOf(false) }
if (showDialogFrom.value) {
DatePickerDialog(
onDismissRequest = { showDialogFrom.value = false },
confirmButton = {
TextButton(onClick = { showDialogFrom.value = false }) {
Text("Ok")
}
},
dismissButton = {
TextButton(onClick = { showDialogFrom.value = false }) {
Text("Cancel")
}
}
) {
DatePicker(state = dateStateFrom)
}
}
val dateStateTo = rememberDatePickerState()
val showDialogTo = rememberSaveable { mutableStateOf(false) }
if (showDialogTo.value) {
DatePickerDialog(
onDismissRequest = { showDialogTo.value = false },
confirmButton = {
TextButton(onClick = { showDialogTo.value = false }) {
Text("Ok")
}
},
dismissButton = {
TextButton(onClick = { showDialogTo.value = false }) {
Text("Cancel")
}
}
) {
DatePicker(state = dateStateTo)
}
}
LazyColumn(
verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.Top),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.fillMaxSize()
.background(color = Color(0xfff4f7fb))
.padding(
horizontal = 5.dp,
vertical = 1.dp
)
) {
item {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth(1f)
.requiredHeight(height = 56.dp)
.background(color = Color.White)
.padding(
horizontal = 17.dp,
vertical = 6.dp
)
) {
Text(
text = "Report",
color = Color.Black,
lineHeight = 1.14.em,
style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Medium
)
)
Text(
text = "Back",
color = Color(0xFFF94B4B),
textAlign = TextAlign.Center,
lineHeight = 0.83.em,
style = TextStyle(
fontSize = 14.sp,
letterSpacing = 0.1.sp
),
modifier = Modifier
.clickable {
navController.navigate(route = BottomBarScreen.Profile.route)
}
.wrapContentHeight(align = Alignment.CenterVertically))
}
}
item {
Button(
onClick = {
showDialogFrom.value = true;
},
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xff4bb2f9)),
modifier = Modifier
.fillMaxWidth()
) {
Text(
if (dateStateFrom.selectedDateMillis != null)
longToDate(dateStateFrom.selectedDateMillis!!).toLocalDate().toString() else
"Select Date"
)
}
Button(
onClick = {
showDialogTo.value = true;
},
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xff4bb2f9)),
modifier = Modifier
.fillMaxWidth()
) {
Text(
if (dateStateTo.selectedDateMillis != null)
longToDate(dateStateTo.selectedDateMillis!!).toLocalDate().toString() else
"Select Date"
)
}
}
item {
Button(
onClick = {
if (dateStateTo.selectedDateMillis != null &&
dateStateFrom.selectedDateMillis != null) {
reportViewModel.setArguments(
user?.id!!,
longToDate(dateStateFrom.selectedDateMillis!!),
longToDate(dateStateTo.selectedDateMillis!!)
)
}
},
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xff4bb2f9)),
modifier = Modifier
.fillMaxWidth()
) {
Text("Create")
}
}
if (deals.isNotEmpty()) {
items(items = deals) {
ReportItem(deal = it, coins = coins)
}
}
else {
item {
Text(text = "No Data")
}
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun ReportItem(modifier: Modifier = Modifier, deal: Deal, coins: List<Coin>) {
Column(
verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.clip(shape = RoundedCornerShape(8.dp))
.background(color = Color.White)
.padding(
horizontal = 12.dp,
vertical = 5.dp
)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(all = 2.dp)
) {
Text(
text = "-${deal.countSell} ${
coins.first { x -> x.id == deal.sellerCoinId }.shortName()
}",
color = Color(0xfff96161),
lineHeight = 1.25.em,
style = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp
),
modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)
)
Text(
text = "->",
color = Color(0xFF009688),
lineHeight = 1.25.em,
style = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp
),
modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)
)
Text(
text = "+${deal.countBuy} ${
coins.first { x -> x.id == deal.buyerCoinId }.shortName()
}",
color = Color(0xff5acb48),
lineHeight = 1.25.em,
style = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp
),
modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)
)
}
}
}

View File

@ -1,25 +1,21 @@
package com.example.testapp.screensMobile package com.example.testapp.screensMobile
import android.annotation.SuppressLint
import android.os.Build import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@ -28,22 +24,22 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.pmulabs.designElem.NavBar import com.example.pmulabs.designElem.NavBar
import com.example.testapp.designElem.ListItem import com.example.testapp.designElem.ListItem
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.graphs.HomeNavGraph import com.example.testapp.graphs.HomeNavGraph
import com.example.testapp.viewModels.AppViewModelProvider import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel import com.example.testapp.viewModels.DealCreateViewModel
import com.example.testapp.viewModels.DealListViewModel import com.example.testapp.viewModels.DealListViewModel
import com.example.testapp.viewModels.HistoryViewModel import com.example.testapp.viewModels.HistoryViewModel
import com.example.testapp.viewModels.ReportViewModel
import com.example.testapp.viewModels.SharedViewModel
import com.example.testapp.viewModels.WalletViewModel import com.example.testapp.viewModels.WalletViewModel
import kotlinx.coroutines.flow.first
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
@ -83,16 +79,16 @@ fun Wallet(
} }
wallet.apply { wallet.apply {
when{ when{
loadState.refresh is LoadState.Loading -> { // loadState.refresh is LoadState.Loading -> {
item { CircularProgressIndicator( // item { CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(0.5f), // modifier = Modifier.fillParentMaxSize(0.5f),
color = Color(0xff423a99)) } // color = Color(0xff423a99)) }
} // }
loadState.append is LoadState.Loading -> { // loadState.append is LoadState.Loading -> {
item { CircularProgressIndicator( // item { CircularProgressIndicator(
modifier = Modifier.fillParentMaxSize(0.5f), // modifier = Modifier.fillParentMaxSize(0.5f),
color = Color(0xff423a99)) } // color = Color(0xff423a99)) }
} // }
loadState.refresh is LoadState.Error -> { loadState.refresh is LoadState.Error -> {
val err = wallet.loadState.refresh as LoadState.Error val err = wallet.loadState.refresh as LoadState.Error
item { Text(err.error.localizedMessage) } item { Text(err.error.localizedMessage) }
@ -116,6 +112,7 @@ fun LoadScreen(
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory), dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory),
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory), historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory),
walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory), walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory),
reportViewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory),
sharedViewModel: SharedViewModel sharedViewModel: SharedViewModel
) { ) {
Scaffold( Scaffold(
@ -130,6 +127,7 @@ fun LoadScreen(
dealListViewModel, dealListViewModel,
historyViewModel, historyViewModel,
walletViewModel, walletViewModel,
reportViewModel,
sharedViewModel sharedViewModel
) )
} }

View File

@ -38,7 +38,7 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.testapp.graphs.AuthScreen import com.example.testapp.graphs.AuthScreen
import com.example.testapp.graphs.Graph import com.example.testapp.graphs.Graph
import com.example.testapp.room.models.User import com.example.testapp.data.room.models.User
import com.example.testapp.viewModels.CurrentUserViewModel import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.RegistrationScreenViewModel import com.example.testapp.viewModels.RegistrationScreenViewModel
import kotlinx.coroutines.async import kotlinx.coroutines.async

View File

@ -1,5 +1,7 @@
package com.example.testapp.viewModels package com.example.testapp.viewModels
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.initializer
@ -7,39 +9,46 @@ import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.testapp.CryptoDealApplication import com.example.testapp.CryptoDealApplication
object AppViewModelProvider { object AppViewModelProvider {
@RequiresApi(Build.VERSION_CODES.O)
val Factory = viewModelFactory { val Factory = viewModelFactory {
initializer {
EntryScreenViewModel(application().container.userRestRepository)
}
initializer { initializer {
CurrentUserViewModel(application().container.userRepository) CurrentUserViewModel(application().container.userRepository)
} }
initializer {
WalletViewModel(
application().container.walletItemRestRepository,
application().container.coinRestRepository
)
}
initializer { initializer {
DealListViewModel( DealListViewModel(
application().container.dealRepository, application().container.dealRestRepository,
application().container.coinRepository, application().container.coinRestRepository,
application().container.walletItemRepository application().container.walletItemRestRepository
) )
} }
initializer { initializer {
DealCreateViewModel( DealCreateViewModel(
application().container.dealRepository, application().container.dealRestRepository,
application().container.coinRepository, application().container.coinRestRepository,
application().container.walletItemRepository application().container.walletItemRestRepository
) )
} }
initializer {
EntryScreenViewModel(application().container.userRepository)
}
initializer { initializer {
HistoryViewModel( HistoryViewModel(
application().container.dealRepository, application().container.dealRestRepository,
application().container.coinRepository application().container.coinRestRepository
) )
} }
initializer { initializer {
RegistrationScreenViewModel(application().container.userRepository) RegistrationScreenViewModel(application().container.userRestRepository)
} }
initializer { initializer {
WalletViewModel( ReportViewModel(
application().container.walletItemRepository, application().container.dealRestRepository,
application().container.coinRepository application().container.coinRepository
) )
} }

View File

@ -1,20 +1,15 @@
package com.example.testapp.viewModels package com.example.testapp.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.testapp.room.models.User import com.example.testapp.data.room.models.User
import com.example.testapp.room.repository.basic.UserRepository import com.example.testapp.data.room.repository.basic.UserRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class CurrentUserViewModel(private val userRepository: UserRepository) : ViewModel() { class CurrentUserViewModel(private val userRepository: UserRepository) : ViewModel() {
val argument = MutableStateFlow<String?>(null) private val argument = MutableStateFlow<String?>(null)
val id = MutableStateFlow<Int?>(null) val id = MutableStateFlow<Int?>(null)
var user = MutableStateFlow<User?>(null) var user = MutableStateFlow<User?>(null)
@ -22,7 +17,7 @@ class CurrentUserViewModel(private val userRepository: UserRepository) : ViewMod
argument.value = arg argument.value = arg
id.value = arg.toInt() id.value = arg.toInt()
viewModelScope.launch { viewModelScope.launch(Dispatchers.IO) {
user.emit(userRepository.getById(id.value!!)) user.emit(userRepository.getById(id.value!!))
} }
} }

View File

@ -1,24 +1,17 @@
package com.example.testapp.viewModels package com.example.testapp.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData import com.example.testapp.data.room.models.Coin
import com.example.testapp.room.models.Coin import com.example.testapp.data.room.models.Deal
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.room.models.WalletItem import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.CoinRepository import com.example.testapp.data.room.repository.basic.DealRepository
import com.example.testapp.room.repository.basic.DealRepository import com.example.testapp.data.room.repository.basic.WalletItemRepository
import com.example.testapp.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class DealCreateViewModel( class DealCreateViewModel(
@ -42,12 +35,8 @@ class DealCreateViewModel(
init { init {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
_coins.emit( _coins.emit(coinRepository.getAll())
coinRepository.getAll().first() _wallet.emit(walletItemRepository.getAll())
)
_wallet.emit(
walletItemRepository.getAll().first()
)
} }
} }

View File

@ -5,15 +5,15 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import com.example.testapp.room.models.Coin import androidx.paging.filter
import com.example.testapp.room.models.Deal import com.example.testapp.data.room.models.Coin
import com.example.testapp.room.models.WalletItem import com.example.testapp.data.room.models.Deal
import com.example.testapp.room.repository.basic.CoinRepository import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.room.repository.basic.DealRepository import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.WalletItemRepository import com.example.testapp.data.room.repository.basic.DealRepository
import com.example.testapp.data.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.Date import java.util.Date
@ -28,19 +28,20 @@ class DealListViewModel(
fun setupLists() { fun setupLists() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
coins.emit(coinRepository.getAll().first()) coins.emit(coinRepository.getAll())
deals.emit(dealRepository deals.emit(dealRepository
.pagingData() .pagingData()
.cachedIn(viewModelScope) .cachedIn(viewModelScope)
.first()) .first()
.filter { it.date == null })
} }
} }
@RequiresApi(34) @RequiresApi(34)
fun submitDeal(deal: Deal, sellerId: Int, buyerId: Int) { fun submitDeal(deal: Deal, sellerId: Int, buyerId: Int) {
viewModelScope.launch { viewModelScope.launch {
val walletSeller: List<WalletItem> = walletItemRepository.getUserWallet(sellerId).first() val walletSeller: List<WalletItem> = walletItemRepository.getUserWallet(sellerId)
val walletBuyer: List<WalletItem> = walletItemRepository.getUserWallet(buyerId).first() val walletBuyer: List<WalletItem> = walletItemRepository.getUserWallet(buyerId)
val seller: WalletItem? = walletSeller.firstOrNull { x -> x.coinId == deal.sellerCoinId } val seller: WalletItem? = walletSeller.firstOrNull { x -> x.coinId == deal.sellerCoinId }
val buyer: WalletItem? = walletBuyer.firstOrNull { x -> x.coinId == deal.buyerId } val buyer: WalletItem? = walletBuyer.firstOrNull { x -> x.coinId == deal.buyerId }
@ -55,7 +56,7 @@ class DealListViewModel(
} }
// Case if need insert // Case if need insert
else { else {
val item = WalletItem(deal.buyerCoinId, sellerId, deal.countBuy) val item = WalletItem(null, deal.buyerCoinId, sellerId, deal.countBuy)
walletItemRepository.insert(item) walletItemRepository.insert(item)
} }
@ -68,7 +69,7 @@ class DealListViewModel(
} }
// Case if need insert // Case if need insert
else { else {
val item = WalletItem(deal.sellerCoinId, buyerId, deal.countSell) val item = WalletItem(null, deal.sellerCoinId, buyerId, deal.countSell)
walletItemRepository.insert(item) walletItemRepository.insert(item)
} }

View File

@ -1,14 +1,10 @@
package com.example.testapp.viewModels package com.example.testapp.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.testapp.room.models.User import com.example.testapp.data.room.models.User
import com.example.testapp.room.repository.basic.UserRepository import com.example.testapp.data.room.repository.basic.UserRepository
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class EntryScreenViewModel( class EntryScreenViewModel(
@ -18,7 +14,7 @@ class EntryScreenViewModel(
fun setupList() { fun setupList() {
viewModelScope.launch { viewModelScope.launch {
userList.emit(userRepository.getAll().first()) userList.emit(userRepository.getAll())
} }
} }
} }

View File

@ -1,14 +1,14 @@
package com.example.testapp.viewModels package com.example.testapp.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.testapp.room.models.Coin import androidx.paging.PagingData
import com.example.testapp.room.models.Deal import androidx.paging.cachedIn
import com.example.testapp.room.repository.basic.CoinRepository import androidx.paging.filter
import com.example.testapp.room.repository.basic.DealRepository import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.data.room.repository.basic.DealRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@ -20,15 +20,26 @@ class HistoryViewModel(
) : ViewModel() { ) : ViewModel() {
val argument = MutableStateFlow<String?>(null) val argument = MutableStateFlow<String?>(null)
private val id = MutableStateFlow<Int?>(null) private val id = MutableStateFlow<Int?>(null)
var deals = MutableStateFlow<List<Deal>>(emptyList()) var deals = MutableStateFlow<PagingData<Deal>>(PagingData.empty())
var coins = MutableStateFlow<List<Coin>>(emptyList()) var coins = MutableStateFlow<List<Coin>>(emptyList())
init {
viewModelScope.launch(Dispatchers.IO) {
deals.emit(dealRepository.pagingData().cachedIn(viewModelScope).first().filter {
x -> x.date == null
})
coins.emit(coinRepository.getAll())
}
}
fun setArgument(arg: String) { fun setArgument(arg: String) {
argument.value = arg argument.value = arg
id.value = arg.toInt() id.value = arg.toInt()
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
deals.emit(dealRepository.getAll().first()) deals.emit(dealRepository.pagingData().cachedIn(viewModelScope).first().filter {
coins.emit(coinRepository.getAll().first()) x -> (x.buyerId == arg.toInt() || x.sellerId == arg.toInt())
})
coins.emit(coinRepository.getAll())
} }
} }
} }

View File

@ -4,9 +4,8 @@ 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 com.example.testapp.room.models.User import com.example.testapp.data.room.models.User
import com.example.testapp.room.repository.basic.UserRepository import com.example.testapp.data.room.repository.basic.UserRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class RegistrationScreenViewModel(private val userRepository: UserRepository) : ViewModel() { class RegistrationScreenViewModel(private val userRepository: UserRepository) : ViewModel() {
@ -15,7 +14,7 @@ class RegistrationScreenViewModel(private val userRepository: UserRepository) :
fun setUserList() { fun setUserList() {
viewModelScope.launch { viewModelScope.launch {
_users.value = userRepository.getAll().first() _users.value = userRepository.getAll()
} }
} }

View File

@ -0,0 +1,49 @@
package com.example.testapp.viewModels
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.testapp.data.room.models.Coin
import com.example.testapp.data.room.models.Deal
import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.data.room.repository.basic.DealRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.ZoneOffset
@RequiresApi(Build.VERSION_CODES.O)
class ReportViewModel(
private val dealRepository: DealRepository,
private val coinRepository: CoinRepository
) : ViewModel() {
private var startDate = MutableStateFlow<LocalDateTime>(LocalDateTime.now().minusDays(1))
private var endDate = MutableStateFlow<LocalDateTime>(LocalDateTime.now())
var deals = MutableStateFlow<List<Deal>>(emptyList())
var coins = MutableStateFlow<List<Coin>>(emptyList())
fun clearLists() {
deals = MutableStateFlow(emptyList())
coins = MutableStateFlow(emptyList())
}
fun setArguments(userId: Int, from : LocalDateTime, to : LocalDateTime) {
viewModelScope.launch(Dispatchers.IO) {
startDate.emit(from)
endDate.emit(to)
val eptf = from.toEpochSecond(ZoneOffset.UTC) * 1000
val eptt = to.toEpochSecond(ZoneOffset.UTC) * 1000
deals.emit(
dealRepository.getUserDeals(userId).filter {
it.date != null &&
it.date!! >= eptf &&
it.date!! <= eptt
}
)
coins.emit(coinRepository.getAll())
}
}
}

View File

@ -0,0 +1,16 @@
package com.example.testapp.viewModels
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import com.example.testapp.data.room.models.Deal
class SharedViewModel : ViewModel() {
var argument_edit = mutableStateOf<Deal?>(null)
fun setArgumentEdit(arg: Deal?) {
if (arg == null) {
argument_edit = mutableStateOf<Deal?>(null)
}
argument_edit.value = arg
}
}

View File

@ -1,24 +1,16 @@
package com.example.testapp.viewModels package com.example.testapp.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import androidx.paging.filter import com.example.testapp.data.room.models.Coin
import com.example.testapp.room.models.Coin import com.example.testapp.data.room.models.WalletItem
import com.example.testapp.room.models.WalletItem import com.example.testapp.data.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.CoinRepository import com.example.testapp.data.room.repository.basic.WalletItemRepository
import com.example.testapp.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -26,17 +18,17 @@ class WalletViewModel(
private val walletItemRepository: WalletItemRepository, private val walletItemRepository: WalletItemRepository,
private val coinRepository: CoinRepository private val coinRepository: CoinRepository
) : ViewModel() { ) : ViewModel() {
val argument = MutableStateFlow<String?>(null) private val argument = MutableStateFlow<String?>(null)
private val id = MutableStateFlow<Int?>(null) private val id = MutableStateFlow<Int?>(null)
var _wallet = MutableStateFlow<PagingData<WalletItem>>(PagingData.empty()) private var _wallet = MutableStateFlow<PagingData<WalletItem>>(PagingData.empty())
var wallet = _wallet.asStateFlow(); var wallet = _wallet.asStateFlow();
var coins = MutableStateFlow<List<Coin>?>(emptyList()) var coins = MutableStateFlow<List<Coin>?>(emptyList())
fun setArgument(arg: String) { fun setArgument(arg: String) {
argument.value = arg argument.value = arg
id.value = arg.toInt() id.value = arg.toInt()
viewModelScope.launch { viewModelScope.launch(Dispatchers.IO) {
coins.emit(coinRepository.getAll().first()) coins.emit(coinRepository.getAll())
_wallet.emit(walletItemRepository _wallet.emit(walletItemRepository
.pagingData(id.value!!) .pagingData(id.value!!)
.cachedIn(viewModelScope) .cachedIn(viewModelScope)

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">172.20.10.13</domain>
</domain-config>
</network-security-config>