add views models and drop func to interfaces

This commit is contained in:
andrew 2023-12-08 13:25:12 +04:00
parent e5adf214b7
commit 5a9c56f573
38 changed files with 1282 additions and 706 deletions

View File

@ -0,0 +1,14 @@
package com.example.testapp
import android.app.Application
import com.example.testapp.room.AppContainer
import com.example.testapp.room.AppDataContainer
class CryptoDealApplication : Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)
}
}

View File

@ -2,26 +2,19 @@ package com.example.testapp
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.widget.TextView
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize import androidx.annotation.RequiresApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.example.testapp.designElem.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 org.w3c.dom.Text import com.example.testapp.viewModels.CurrentUserViewModel
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val sharedViewModel: SharedViewModel by viewModels() private val currentUserViewModel: CurrentUserViewModel by viewModels()
@RequiresApi(34)
@SuppressLint("MissingInflatedId", "SetTextI18n") @SuppressLint("MissingInflatedId", "SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -29,7 +22,7 @@ class MainActivity : ComponentActivity() {
TestAppTheme { TestAppTheme {
RootNavigationGraph( RootNavigationGraph(
navController = rememberNavController(), navController = rememberNavController(),
sharedViewModel = sharedViewModel currentUserViewModel = currentUserViewModel
) )
} }
} }

View File

@ -5,25 +5,42 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.navigation import androidx.navigation.navigation
import com.example.testapp.designElem.SharedViewModel import com.example.testapp.screensMobile.authScreens.EntryScreen
import com.example.testapp.screensMobile.EntryScreen import com.example.testapp.screensMobile.authScreens.RegisterScreen
import com.example.testapp.screensMobile.RegisterScreen import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.EntryScreenViewModel
import com.example.testapp.viewModels.RegistrationScreenViewModel
fun NavGraphBuilder.authNavGraph(navController: NavHostController, sharedViewModel: SharedViewModel){ fun NavGraphBuilder.authNavGraph(
navController: NavHostController,
currentUserViewModel: CurrentUserViewModel,
entryScreenViewModel: EntryScreenViewModel,
registrationScreenViewModel: RegistrationScreenViewModel
) {
navigation( navigation(
route=Graph.AUTHENTICATION, route = Graph.AUTHENTICATION,
startDestination = AuthScreen.Entry.route startDestination = AuthScreen.Entry.route
){ ) {
composable(route=AuthScreen.Entry.route){ composable(route = AuthScreen.Entry.route) {
EntryScreen(navController = navController, modifier = Modifier, sharedViewModel = sharedViewModel) EntryScreen(
navController,
Modifier,
currentUserViewModel,
entryScreenViewModel
)
} }
composable(route=AuthScreen.Register.route){ composable(route = AuthScreen.Register.route) {
RegisterScreen(navController = navController, modifier = Modifier, sharedViewModel = sharedViewModel) RegisterScreen(
navController,
Modifier,
currentUserViewModel,
registrationScreenViewModel
)
} }
} }
} }
sealed class AuthScreen(val route: String){ sealed class AuthScreen(val route: String) {
object Entry : AuthScreen(route="ENTRY") object Entry : AuthScreen(route = "ENTRY")
object Register : AuthScreen(route="REGISTER") object Register : AuthScreen(route = "REGISTER")
} }

View File

@ -1,44 +1,72 @@
package com.example.testapp.graphs package com.example.testapp.graphs
import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
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 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.Wallet import com.example.testapp.screensMobile.Wallet
import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel
import com.example.testapp.viewModels.DealListViewModel
import com.example.testapp.viewModels.HistoryViewModel
import com.example.testapp.viewModels.WalletViewModel
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun HomeNavGraph(navController: NavHostController, sharedViewModel: SharedViewModel){ fun HomeNavGraph(
navController: NavHostController,
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealCreateViewModel: DealCreateViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory),
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory),
walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
NavHost( NavHost(
navController = navController, navController = navController,
route = Graph.MAIN, route = Graph.MAIN,
startDestination = BottomBarScreen.Wallet.route startDestination = BottomBarScreen.Wallet.route
){ ) {
composable(route=BottomBarScreen.Wallet.route){ composable(route = BottomBarScreen.Wallet.route) {
Wallet(sharedViewModel = sharedViewModel) Wallet(
navController = navController,
currentUserViewModel = currentUserViewModel,
walletViewModel = walletViewModel
)
} }
composable(route=BottomBarScreen.Profile.route){ composable(route = BottomBarScreen.Profile.route) {
AccountPage(sharedViewModel = sharedViewModel, navController = navController) AccountPage(
navController = navController,
currentUserViewModel = currentUserViewModel
)
} }
composable(route=BottomBarScreen.Deals.route){ composable(route = BottomBarScreen.Deals.route) {
DealList(navController = navController, sharedViewModel = sharedViewModel) DealList(
navController = navController,
currentUserViewModel = currentUserViewModel,
dealListViewModel = dealListViewModel
)
} }
composable(route=BottomBarScreen.CDEAL.route) { composable(route = BottomBarScreen.CDEAL.route) {
CreateDeal(sharedViewModel = sharedViewModel, navController = navController) CreateDeal(
navController = navController,
currentUserViewModel = currentUserViewModel,
dealCreateViewModel = dealCreateViewModel
)
} }
composable(route=BottomBarScreen.History.route){ composable(route = BottomBarScreen.History.route) {
History(sharedViewModel = sharedViewModel) History(
navController = navController,
currentUserViewModel = currentUserViewModel,
historyViewModel = historyViewModel
)
} }
} }
} }

View File

@ -1,42 +1,71 @@
package com.example.testapp.graphs package com.example.testapp.graphs
import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavType 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.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel
import com.example.testapp.viewModels.DealListViewModel
import com.example.testapp.viewModels.EntryScreenViewModel
import com.example.testapp.viewModels.HistoryViewModel
import com.example.testapp.viewModels.RegistrationScreenViewModel
import com.example.testapp.viewModels.WalletViewModel
const val USERID_ARGUMENT="userId" const val USERID_ARGUMENT = "userId"
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun RootNavigationGraph(navController: NavHostController, sharedViewModel: SharedViewModel){ fun RootNavigationGraph(
navController: NavHostController,
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealCreateViewModel: DealCreateViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory),
entryScreenViewModel: EntryScreenViewModel = viewModel(factory = AppViewModelProvider.Factory),
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory),
registrationScreenViewModel: RegistrationScreenViewModel = viewModel(factory = AppViewModelProvider.Factory),
walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
NavHost( NavHost(
navController=navController, navController = navController,
route = Graph.ROOT, route = Graph.ROOT,
startDestination = Graph.AUTHENTICATION startDestination = Graph.AUTHENTICATION
){ ) {
authNavGraph(navController=navController,sharedViewModel) authNavGraph(
composable(route=Graph.MAIN, navController = navController,
arguments = listOf(navArgument(USERID_ARGUMENT){ currentUserViewModel,
type= NavType.StringType entryScreenViewModel,
})){ registrationScreenViewModel
LoadScreen(sharedViewModel = sharedViewModel) )
composable(
route = Graph.MAIN,
arguments = listOf(navArgument(USERID_ARGUMENT) {
type = NavType.StringType
})
) {
LoadScreen(
currentUserViewModel = currentUserViewModel,
dealCreateViewModel = dealCreateViewModel,
dealListViewModel = dealListViewModel,
historyViewModel = historyViewModel,
walletViewModel = walletViewModel
)
} }
} }
} }
object Graph{ object Graph {
const val ROOT="root_graph" const val ROOT = "root_graph"
const val AUTHENTICATION="auth_graph" const val AUTHENTICATION = "auth_graph"
const val MAIN="main_graph/{$USERID_ARGUMENT}" const val MAIN = "main_graph/{$USERID_ARGUMENT}"
fun passUserId(userId: String): String{ fun passUserId(userId: String): String {
return "main_graph/$userId" return "main_graph/$userId"
} }
} }

View File

@ -0,0 +1,40 @@
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,21 +1,12 @@
package com.example.testapp.room.dao package com.example.testapp.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Update
import com.example.testapp.room.models.Coin import com.example.testapp.room.models.Coin
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface CoinDao{ interface CoinDao : IDao<Coin> {
@Query("select * from coin") @Query("select * from coin")
fun getAll(): Flow<List<Coin>> fun getAll(): Flow<List<Coin>>
@Insert
suspend fun insert(obj: Coin)
@Update
suspend fun update(obj: Coin)
@Delete
suspend fun delete(obj: Coin)
} }

View File

@ -1,24 +1,18 @@
package com.example.testapp.room.dao package com.example.testapp.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Update
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal import com.example.testapp.room.models.Deal
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface DealDao{ interface DealDao : IDao<Deal> {
@Query("select * from deal") @Query("select * from deal")
fun getAll(): Flow<List<Deal>> fun getAll(): Flow<List<Deal>>
@Query("select * from deal ORDER BY id DESC LIMIT :limit OFFSET :offset")
fun getAll(limit: Int, offset: Int): List<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>>
@Insert
suspend fun insert(obj: Deal)
@Update
suspend fun update(obj: Deal)
@Delete
suspend fun delete(obj: Deal)
} }

View File

@ -0,0 +1,18 @@
package com.example.testapp.room.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Update
@Dao
interface IDao<T> {
@Insert
suspend fun insert(obj: T)
@Update
suspend fun update(obj: T)
@Delete
suspend fun delete(obj: T)
}

View File

@ -1,29 +1,23 @@
package com.example.testapp.room.dao package com.example.testapp.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Update
import com.example.testapp.room.models.Deal import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.User import com.example.testapp.room.models.User
import com.example.testapp.room.models.WalletItem import com.example.testapp.room.models.WalletItem
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface UserDao { interface UserDao : IDao<User> {
@Query("select * from user") @Query("select * from user")
fun getAll(): Flow<List<User>> fun getAll(): Flow<List<User>>
@Query("select * from user where user.id = :idUser") @Query("select * from user where user.id = :idUser")
fun getUserById(idUser: Int): Flow<User> fun getUserById(idUser: Int): Flow<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): Flow<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): Flow<List<Deal>>
@Insert
fun insert(obj: User)
@Update
fun update(obj: User)
@Delete
fun delete(obj: User)
} }

View File

@ -1,23 +1,15 @@
package com.example.testapp.room.dao package com.example.testapp.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Update
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.models.WalletItem
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface WalletItemDao { interface WalletItemDao : IDao<WalletItem> {
@Query("select * from walletitem") @Query("select * from walletitem")
fun getAll(): Flow<List<WalletItem>> fun getAll(): Flow<List<WalletItem>>
@Insert
suspend fun insert(obj: WalletItem) @Query("select * from walletitem where walletitem.userId = :id")
@Update fun getUserWallet(id: Int): Flow<List<WalletItem>>
suspend fun update(obj: WalletItem)
@Delete
suspend fun delete(obj: WalletItem)
} }

View File

@ -0,0 +1,38 @@
package com.example.testapp.room.pagination
import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.example.testapp.room.dao.DealDao
import com.example.testapp.room.models.Deal
import kotlinx.coroutines.delay
class DealPagination(
private val dao: DealDao
) : PagingSource<Int, Deal>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Deal> {
val page = params.key ?: 0
return try {
Log.d("MainPagingSource", "load: $page")
val entities = dao.getAll(params.loadSize, page * params.loadSize)
if (page != 0) delay(1000)
LoadResult.Page(
data = entities,
prevKey = if (page == 0) null else page - 1,
nextKey = if (entities.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override val jumpingSupported: Boolean = true
override fun getRefreshKey(state: PagingState<Int, Deal>): Int? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
package com.example.testapp.room.repository.basic
import com.example.testapp.room.models.Deal
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
}

View File

@ -0,0 +1,12 @@
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 getAll(): Flow<List<T>>
fun getById(id: Int): Flow<T>
fun getAll(limit: Int, offset: Int): List<T>
}

View File

@ -0,0 +1,11 @@
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

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

View File

@ -0,0 +1,14 @@
package com.example.testapp.room.repository.offline
import com.example.testapp.room.dao.CoinDao
import com.example.testapp.room.models.Coin
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 getAll(limit: Int, offset: Int): List<Coin> = throw NotImplementedError()
override fun getById(id: Int): Flow<Coin> = throw NotImplementedError()
}

View File

@ -0,0 +1,43 @@
package com.example.testapp.room.repository.offline
import com.example.testapp.room.dao.DealDao
import com.example.testapp.room.models.Deal
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 getAll(limit: Int, offset: Int) = dealDao.getAll(limit, offset)
override fun getById(id: Int): Flow<Deal> = throw NotImplementedError()
override fun getUserDeals(id: Int): Flow<List<Deal>> = dealDao.getUserDeals(id)
override fun completeDeal(deal: Deal, sellerId: Int, buyerId: Int): Boolean {
// val userRepository = UserRepository()
// val buyer = deal.buyerId?.let { userRepository.getById(it) }
// val seller = userRepository.getById(id)
//
// val coin = seller.wallet[deal.sellerCoin]
// if (coin != null && coin >= deal.countSell) {
// if (buyer != null) {
// if (buyer.wallet.containsKey(deal.sellerCoin))
// buyer.wallet[deal.sellerCoin] = buyer.wallet[deal.sellerCoin]!! + deal.countSell
// else buyer.wallet[deal.sellerCoin] = deal.countSell
// buyer.wallet[deal.buyerCoin] = buyer.wallet[deal.buyerCoin]!! - deal.countBuy
// }
// seller.wallet[deal.sellerCoin] = seller.wallet[deal.sellerCoin]!! - deal.countSell
// if (seller.wallet.containsKey(deal.buyerCoin))
// seller.wallet[deal.buyerCoin] = seller.wallet[deal.buyerCoin]!! + deal.countBuy
// else seller.wallet[deal.buyerCoin] = deal.countSell
// }
// deal.date = LocalDateTime.now()
// deal.sellerId = id
// DealRepository().update(deal)
// navController.navigate(BottomBarScreen.Deals.route) {
// popUpTo(navController.graph.findStartDestination().id)
// launchSingleTop = true
// }
return true;
}
}

View File

@ -0,0 +1,12 @@
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

@ -0,0 +1,18 @@
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 getAll(limit: Int, offset: Int) = throw NotImplementedError()
override fun getById(id: Int): Flow<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

@ -0,0 +1,15 @@
package com.example.testapp.room.repository.offline
import com.example.testapp.room.dao.WalletItemDao
import com.example.testapp.room.models.WalletItem
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 getAll(limit: Int, offset: Int): List<WalletItem> = throw NotImplementedError()
override fun getById(id: Int): Flow<WalletItem> = throw NotImplementedError()
}

View File

@ -19,44 +19,36 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember 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.platform.LocalContext
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
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.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.graphs.AuthScreen import com.example.testapp.graphs.AuthScreen
import com.example.testapp.room.database.CryptoDealDb import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.room.models.User import com.example.testapp.viewModels.CurrentUserViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@SuppressLint("CoroutineCreationDuringComposition") @SuppressLint("CoroutineCreationDuringComposition")
@Composable @Composable
fun AccountPage(modifier: Modifier = Modifier, sharedViewModel: SharedViewModel, navController: NavController) { fun AccountPage(
val argument = sharedViewModel.argument.value modifier: Modifier = Modifier,
val context = LocalContext.current navController: NavController,
val users = remember { mutableStateListOf<User>() } currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
var user: User? = null; ) {
CoroutineScope(Dispatchers.IO).launch { val user by remember { mutableStateOf(currentUserViewModel.user) }
CryptoDealDb.getInstance(context).userDao().getUserById(argument!!.toInt()).collect { data -> val coroutineScope = rememberCoroutineScope()
user = data
}
}
Box( Box(
modifier = modifier modifier = modifier
@ -86,7 +78,9 @@ fun AccountPage(modifier: Modifier = Modifier, sharedViewModel: SharedViewModel,
if (user != null) { if (user != null) {
Container( Container(
name = user!!.email.substring(0, 2), name = user!!.email.substring(0, 2),
modifier = Modifier.align(alignment = Alignment.TopStart).offset(15.dp, 15.dp) modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(15.dp, 15.dp)
) )
} }
} }
@ -107,13 +101,16 @@ fun AccountPage(modifier: Modifier = Modifier, sharedViewModel: SharedViewModel,
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
} }
} }
Box( Box(
modifier = Modifier modifier = Modifier
.requiredWidth(width = 17.dp) .requiredWidth(width = 17.dp)
.requiredHeight(height = 4.dp)) .requiredHeight(height = 4.dp)
)
} }
} }
} }
@ -135,7 +132,8 @@ fun AccountPage(modifier: Modifier = Modifier, sharedViewModel: SharedViewModel,
.offset( .offset(
x = 0.dp, x = 0.dp,
y = 24.dp y = 24.dp
)) )
)
} }
} }
@ -169,10 +167,12 @@ fun Property1Switch(modifier: Modifier = Modifier) {
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.weight(weight = 1f) .weight(weight = 1f)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
Viewchecked() Viewchecked()
} }
} }
@ -194,9 +194,11 @@ fun Container(modifier: Modifier = Modifier, name: String) {
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = TextStyle( style = TextStyle(
fontSize = 24.sp, fontSize = 24.sp,
fontWeight = FontWeight.Medium), fontWeight = FontWeight.Medium
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
} }
@ -216,12 +218,14 @@ fun Viewchecked(modifier: Modifier = Modifier) {
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.clip(shape = RoundedCornerShape(100.dp)) .clip(shape = RoundedCornerShape(100.dp))
.background(color = Color(0xff4bb2f9))) .background(color = Color(0xff4bb2f9))
)
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.clip(shape = CircleShape) .clip(shape = CircleShape)
.background(color = Color.White)) .background(color = Color.White)
)
} }
} }
} }
@ -256,10 +260,12 @@ fun Property1Arrow(modifier: Modifier = Modifier) {
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.weight(weight = 1f) .weight(weight = 1f)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
} }
@ -269,7 +275,7 @@ fun Property1Clear(modifier: Modifier = Modifier, navController: NavController)
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.clip(shape = RoundedCornerShape(10.dp)) .clip(shape = RoundedCornerShape(10.dp))
.clickable{ .clickable {
navController.navigate(route = AuthScreen.Entry.route) { navController.navigate(route = AuthScreen.Entry.route) {
popUpTo(navController.graph.findStartDestination().id) popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = true launchSingleTop = true
@ -302,7 +308,9 @@ fun Property1Clear(modifier: Modifier = Modifier, navController: NavController)
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
} }
} }
} }
@ -343,9 +351,11 @@ fun Property1(modifier: Modifier = Modifier) {
lineHeight = 1.14.em, lineHeight = 1.14.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium), fontWeight = FontWeight.Medium
),
modifier = Modifier modifier = Modifier
.fillMaxWidth()) .fillMaxWidth()
)
} }
} }
} }

View File

@ -1,5 +1,6 @@
package com.example.testapp.screensMobile package com.example.testapp.screensMobile
import android.annotation.SuppressLint
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -20,11 +21,8 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
@ -33,66 +31,47 @@ 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.platform.LocalContext
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
import androidx.compose.ui.tooling.preview.Preview
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.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
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.database.CryptoDealDb
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.User import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.room.models.WalletItem import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.DealCreateViewModel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@SuppressLint("UnrememberedMutableState")
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun CreateDeal(modifier: Modifier = Modifier, fun CreateDeal(
sharedViewModel: SharedViewModel, modifier: Modifier = Modifier,
navController: NavHostController) { navController: NavHostController,
val argument = sharedViewModel.argument.value currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
val editDeal: Deal? = sharedViewModel.argument_edit.value as? Deal dealCreateViewModel: DealCreateViewModel = viewModel(factory = AppViewModelProvider.Factory)
val isEdit = editDeal != null ) {
val id = if (isEdit) editDeal?.buyerId else argument?.toInt() dealCreateViewModel.setupLists(currentUserViewModel.user!!.id.toString())
val context = LocalContext.current val isEdit = dealCreateViewModel.isEdit()
val coins = remember { mutableStateListOf<Coin>() } val editDeal: Deal? = dealCreateViewModel.deal
SideEffect() { val id = if (isEdit) editDeal?.buyerId else currentUserViewModel.user!!.id
CoroutineScope(Dispatchers.IO).launch {
CryptoDealDb.getInstance(context).coinDao().getAll().collect { data ->
coins.clear()
coins.addAll(data)
}
}
}
val wallet = remember { mutableStateListOf<WalletItem>() } val coins = mutableStateOf(dealCreateViewModel.coins)
LaunchedEffect(Unit) { val wallet = mutableStateOf(dealCreateViewModel.wallet)
withContext(Dispatchers.IO) {
if (id != null) {
CryptoDealDb.getInstance(context).userDao().getUserWallet(id).collect{data ->
wallet.clear();
wallet.addAll(data);
}
}
}
}
val coinsBuyer = wallet.filter { x -> x.userId == id }.toList()
val coinsBuyer = wallet.value.filter { x -> x.userId == id }.toList()
var coinBuyer by rememberSaveable { var coinBuyer by rememberSaveable {
mutableStateOf(if (isEdit) coins.first{y -> y.id == editDeal?.buyerCoinId }.name else coinsBuyer[0]) mutableStateOf(if (isEdit) coins.value.first { y -> y.id == editDeal?.buyerCoinId }.name else coinsBuyer[0])
} }
var buyCount by remember { var buyCount by remember {
@ -102,9 +81,10 @@ fun CreateDeal(modifier: Modifier = Modifier,
mutableStateOf(if (isEdit) editDeal?.tip else "") mutableStateOf(if (isEdit) editDeal?.tip else "")
} }
val coinsSeller = wallet.map { x -> coins.first{y -> y.id == x.coinId}.name }.toList() val coinsSeller =
wallet.value.map { x -> coins.value.first { y -> y.id == x.coinId }.name }.toList()
var coinSeller by rememberSaveable { var coinSeller by rememberSaveable {
mutableStateOf(if (isEdit) coins.first{y -> y.id == editDeal?.sellerCoinId }.name else coinsSeller[0]) mutableStateOf(if (isEdit) coins.value.first { y -> y.id == editDeal?.sellerCoinId }.name else coinsSeller[0])
} }
var sellCount by remember { var sellCount by remember {
mutableFloatStateOf(if (isEdit) editDeal?.countSell!! else 0f) mutableFloatStateOf(if (isEdit) editDeal?.countSell!! else 0f)
@ -141,7 +121,8 @@ fun CreateDeal(modifier: Modifier = Modifier,
lineHeight = 1.14.em, lineHeight = 1.14.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium) fontWeight = FontWeight.Medium
)
) )
Text( Text(
text = "-", text = "-",
@ -150,7 +131,8 @@ fun CreateDeal(modifier: Modifier = Modifier,
lineHeight = 0.83.em, lineHeight = 0.83.em,
style = TextStyle( style = TextStyle(
fontSize = 24.sp, fontSize = 24.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.clickable { .clickable {
navController.navigate(route = BottomBarScreen.Deals.route) navController.navigate(route = BottomBarScreen.Deals.route)
@ -165,15 +147,18 @@ fun CreateDeal(modifier: Modifier = Modifier,
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
item { item {
DropDown( DropDown(
modifier = Modifier.padding(horizontal = 10.dp), modifier = Modifier.padding(horizontal = 10.dp),
downConfig = DropDownConfig<String>( downConfig = DropDownConfig<String>(
values = coinsBuyer.map { x -> coins.first{y -> y.id == x.coinId}.name }.toList(), values = coinsBuyer.map { x -> coins.value.first { y -> y.id == x.coinId }.name }
.toList(),
title = "Select coin", title = "Select coin",
onValueChange = { x -> coinBuyer = x }, onValueChange = { x -> coinBuyer = x },
selected = coinBuyer as String selected = coinBuyer as String
@ -184,22 +169,25 @@ fun CreateDeal(modifier: Modifier = Modifier,
OutlinedTextField( OutlinedTextField(
value = buyCount.toString(), value = buyCount.toString(),
onValueChange = { onValueChange = {
val value = coinsBuyer.first{ x -> coinBuyer == coins.first{y -> y.id == x.coinId} } val value =
if (it.toFloatOrNull() != null && it.toFloat() <= value.count) { coinsBuyer.first { x -> coinBuyer == coins.value.first { y -> y.id == x.coinId } }
buyCount = it.toFloat() if (it.toFloatOrNull() != null && it.toFloat() <= value.count) {
} buyCount = it.toFloat()
}
}, },
label = { label = {
Text( Text(
text = "Fill count 0 -> ${coinsBuyer.first{ x -> coinBuyer == coins.first{y -> y.id == x.coinId} }.count}", text = "Fill count 0 -> ${coinsBuyer.first { x -> coinBuyer == coins.value.first { y -> y.id == x.coinId } }.count}",
color = Color.Black, color = Color.Black,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
lineHeight = 1.43.em, lineHeight = 1.43.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
}, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -207,7 +195,8 @@ fun CreateDeal(modifier: Modifier = Modifier,
.padding( .padding(
horizontal = 10.dp, horizontal = 10.dp,
vertical = 2.dp vertical = 2.dp
)) )
)
} }
item { item {
OutlinedTextField( OutlinedTextField(
@ -221,9 +210,11 @@ fun CreateDeal(modifier: Modifier = Modifier,
lineHeight = 1.43.em, lineHeight = 1.43.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
}, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -232,7 +223,8 @@ fun CreateDeal(modifier: Modifier = Modifier,
.padding( .padding(
horizontal = 10.dp, horizontal = 10.dp,
vertical = 2.dp vertical = 2.dp
)) )
)
} }
item { item {
Text( Text(
@ -241,9 +233,11 @@ fun CreateDeal(modifier: Modifier = Modifier,
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
item { item {
DropDown( DropDown(
@ -268,9 +262,11 @@ fun CreateDeal(modifier: Modifier = Modifier,
lineHeight = 1.43.em, lineHeight = 1.43.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
}, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -278,7 +274,8 @@ fun CreateDeal(modifier: Modifier = Modifier,
.padding( .padding(
horizontal = 10.dp, horizontal = 10.dp,
vertical = 2.dp vertical = 2.dp
)) )
)
} }
item { item {
Button( Button(
@ -288,32 +285,32 @@ fun CreateDeal(modifier: Modifier = Modifier,
id = editDeal?.id, id = editDeal?.id,
sellerId = editDeal?.sellerId, sellerId = editDeal?.sellerId,
buyerId = id, buyerId = id,
buyerCoinId = coins.first { x -> x.name == coinBuyer }.id!!, buyerCoinId = coins.value.first { x -> x.name == coinBuyer }.id!!,
countBuy = buyCount, countBuy = buyCount,
sellerCoinId = coins.first { x -> x.name == coinSeller }.id!!, sellerCoinId = coins.value.first { x -> x.name == coinSeller }.id!!,
countSell = sellCount, countSell = sellCount,
tip = tip!!, tip = tip!!,
operation = "Buy", operation = "Buy",
date = null, date = null,
) )
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
CryptoDealDb.getInstance(context).dealDao().update(deal) dealCreateViewModel.update(deal)
} }
} else { } else {
val deal = Deal( val deal = Deal(
id = null, id = null,
sellerId = null, sellerId = null,
buyerId = id, buyerId = id,
buyerCoinId = coins.first { x -> x.name == coinBuyer }.id!!, buyerCoinId = coins.value.first { x -> x.name == coinBuyer }.id!!,
countBuy = buyCount, countBuy = buyCount,
sellerCoinId = coins.first { x -> x.name == coinSeller }.id!!, sellerCoinId = coins.value.first { x -> x.name == coinSeller }.id!!,
countSell = sellCount, countSell = sellCount,
tip = tip!!, tip = tip!!,
operation = "Buy", operation = "Buy",
date = null, date = null,
) )
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
CryptoDealDb.getInstance(context).dealDao().insert(deal) dealCreateViewModel.create(deal)
} }
} }
navController.navigate(route = BottomBarScreen.Deals.route) navController.navigate(route = BottomBarScreen.Deals.route)
@ -350,7 +347,9 @@ fun CreateDeal(modifier: Modifier = Modifier,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
} }
} }
} }
@ -393,23 +392,13 @@ fun CreateDeal(modifier: Modifier = Modifier,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
} }
} }
} }
} }
} }
} }
}
@RequiresApi(34)
@Preview
@Composable
private fun Frame20Preview() {
val sharedViewModel = SharedViewModel()
sharedViewModel.setArgument("0")
CreateDeal(Modifier,
navController = rememberNavController(),
sharedViewModel = sharedViewModel
)
} }

View File

@ -1,37 +1,28 @@
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.BorderStroke
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
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.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
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.offset
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.requiredSize import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.requiredWidth import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember 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
@ -39,73 +30,40 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
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
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.compose.ui.window.Dialog import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.testapp.R
import com.example.testapp.designElem.AlertDialogExample
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.graphs.Graph
import com.example.testapp.navigate.BottomBarScreen import com.example.testapp.navigate.BottomBarScreen
import com.example.testapp.room.database.CryptoDealDb
import com.example.testapp.room.models.Coin import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal import com.example.testapp.room.models.Deal
import com.example.testapp.room.models.WalletItem import com.example.testapp.viewModels.AppViewModelProvider
import kotlinx.coroutines.Dispatchers import com.example.testapp.viewModels.CurrentUserViewModel
import kotlinx.coroutines.withContext import com.example.testapp.viewModels.DealCreateViewModel
import java.time.LocalDate import com.example.testapp.viewModels.DealListViewModel
import java.time.LocalDateTime
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun DealList(navController: NavHostController, fun DealList(
sharedViewModel: SharedViewModel, modifier: Modifier = Modifier,
@SuppressLint("ModifierParameter") modifier: Modifier = Modifier navController: NavHostController,
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealCreateViewModel: DealCreateViewModel = viewModel(factory = AppViewModelProvider.Factory)
) { ) {
val argument = sharedViewModel.argument.value val id = currentUserViewModel.user!!.id
val id = argument?.toInt() dealListViewModel.setupLists()
val context = LocalContext.current val deals = remember { mutableStateOf(dealListViewModel.deals) }
val deals = remember { mutableStateListOf<Deal>() } val coins = remember { mutableStateOf(dealListViewModel.coins) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
CryptoDealDb.getInstance(context).dealDao().getAll().collect { data ->
deals.clear()
deals.addAll(data)
}
}
}
val wallet = remember { mutableStateListOf<WalletItem>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
if (id != null) {
CryptoDealDb.getInstance(context).userDao().getUserWallet(id).collect{data ->
wallet.clear();
wallet.addAll(data);
}
}
}
}
val coins = remember { mutableStateListOf<Coin>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
CryptoDealDb.getInstance(context).coinDao().getAll().collect { data ->
coins.clear()
coins.addAll(data)
}
}
}
LazyColumn ( LazyColumn(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier modifier = modifier
@ -117,27 +75,32 @@ fun DealList(navController: NavHostController,
PropertyDeal(navController = navController) PropertyDeal(navController = navController)
} }
item { item {
deals.filter { x -> x.date == null }.forEach{ x -> Deal( deals.value.filter { x -> x.date == null }.forEach { x ->
deal = x, DealItem(
coins = coins, deal = x,
modifier = Modifier.padding(vertical = 5.dp), coins = coins.value,
id = id, modifier = Modifier.padding(vertical = 5.dp),
navController = navController, id = id,
sharedViewModel = sharedViewModel, navController = navController,
wallet = wallet)} dealCreateViewModel = dealCreateViewModel,
dealListViewModel = dealListViewModel
)
}
} }
} }
} }
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun Deal(modifier: Modifier = Modifier, fun DealItem(
deal: Deal, modifier: Modifier = Modifier,
coins: List<Coin>, deal: Deal,
id: Int?, coins: List<Coin>,
navController: NavHostController, id: Int?,
sharedViewModel: SharedViewModel, navController: NavHostController,
wallet: List<WalletItem>) { dealCreateViewModel: DealCreateViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
Column( Column(
verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top), verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.Top),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
@ -177,14 +140,16 @@ fun Deal(modifier: Modifier = Modifier,
) )
) { ) {
Text( Text(
text = coins.first{x -> x.id == deal.buyerCoinId}.shortName(), text = coins.first { x -> x.id == deal.buyerCoinId }.shortName(),
color = Color.White, color = Color.White,
lineHeight = 1.em, lineHeight = 1.em,
style = TextStyle( style = TextStyle(
fontSize = 20.sp, fontSize = 20.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
Text( Text(
text = deal.countBuy.toString(), text = deal.countBuy.toString(),
@ -193,10 +158,12 @@ fun Deal(modifier: Modifier = Modifier,
lineHeight = 1.em, lineHeight = 1.em,
style = TextStyle( style = TextStyle(
fontSize = 20.sp, fontSize = 20.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
Text( Text(
text = deal.tip, text = deal.tip,
@ -206,11 +173,13 @@ fun Deal(modifier: Modifier = Modifier,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.requiredHeight(height = 40.dp) .requiredHeight(height = 40.dp)
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
Row( Row(
horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally), horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@ -225,33 +194,9 @@ fun Deal(modifier: Modifier = Modifier,
Button( Button(
onClick = { onClick = {
if (id != null && id != deal.buyerId) { if (id != null && id != deal.buyerId) {
// val userRepository = UserRepository() deal.buyerId?.let { dealListViewModel.submitDeal(deal, id, it) }
// val buyer = deal.buyerId?.let { userRepository.getById(it) }
// val seller = userRepository.getById(id)
//
// val coin = seller.wallet[deal.sellerCoin]
// if (coin != null && coin >= deal.countSell) {
// if (buyer != null) {
// if (buyer.wallet.containsKey(deal.sellerCoin))
// buyer.wallet[deal.sellerCoin] = buyer.wallet[deal.sellerCoin]!! + deal.countSell
// else buyer.wallet[deal.sellerCoin] = deal.countSell
// buyer.wallet[deal.buyerCoin] = buyer.wallet[deal.buyerCoin]!! - deal.countBuy
// }
// seller.wallet[deal.sellerCoin] = seller.wallet[deal.sellerCoin]!! - deal.countSell
// if (seller.wallet.containsKey(deal.buyerCoin))
// seller.wallet[deal.buyerCoin] = seller.wallet[deal.buyerCoin]!! + deal.countBuy
// else seller.wallet[deal.buyerCoin] = deal.countSell
// }
// deal.date = LocalDateTime.now()
// deal.sellerId = id
// DealRepository().update(deal)
// navController.navigate(BottomBarScreen.Deals.route) {
// popUpTo(navController.graph.findStartDestination().id)
// launchSingleTop = true
// }
} else { } else {
sharedViewModel.setArgumentEdit(deal) deal.id?.let { dealCreateViewModel.setupEdit(it) }
sharedViewModel.setArgumentAdd(wallet, coins)
navController.navigate(BottomBarScreen.CDEAL.route) { navController.navigate(BottomBarScreen.CDEAL.route) {
popUpTo(navController.graph.findStartDestination().id) popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = true launchSingleTop = true
@ -265,7 +210,10 @@ fun Deal(modifier: Modifier = Modifier,
.weight(weight = 0.5f) .weight(weight = 0.5f)
) { ) {
Row( Row(
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), horizontalArrangement = Arrangement.spacedBy(
10.dp,
Alignment.CenterHorizontally
),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.requiredWidth(width = 168.dp) .requiredWidth(width = 168.dp)
@ -278,9 +226,11 @@ fun Deal(modifier: Modifier = Modifier,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.requiredWidth(width = 29.dp)) .requiredWidth(width = 29.dp)
)
} }
} }
Row( Row(
@ -294,14 +244,16 @@ fun Deal(modifier: Modifier = Modifier,
.padding(horizontal = 10.dp) .padding(horizontal = 10.dp)
) { ) {
Text( Text(
text = coins.first{x -> x.id == deal.sellerCoinId}.shortName(), text = coins.first { x -> x.id == deal.sellerCoinId }.shortName(),
color = Color.White, color = Color.White,
textAlign = TextAlign.End, textAlign = TextAlign.End,
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
Text( Text(
text = "${deal.countSell}\n", text = "${deal.countSell}\n",
color = Color.White, color = Color.White,
@ -310,10 +262,12 @@ fun Deal(modifier: Modifier = Modifier,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.requiredHeight(height = 20.dp)) .requiredHeight(height = 20.dp)
)
} }
} }
} }
@ -345,7 +299,9 @@ fun PropertyDeal(modifier: Modifier = Modifier, navController: NavHostController
lineHeight = 1.14.em, lineHeight = 1.14.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium)) fontWeight = FontWeight.Medium
)
)
Text( Text(
text = "+", text = "+",
color = Color(0xff4bb2f9), color = Color(0xff4bb2f9),
@ -353,7 +309,8 @@ fun PropertyDeal(modifier: Modifier = Modifier, navController: NavHostController
lineHeight = 0.83.em, lineHeight = 0.83.em,
style = TextStyle( style = TextStyle(
fontSize = 24.sp, fontSize = 24.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.clickable { .clickable {
navController.navigate(BottomBarScreen.CDEAL.route) { navController.navigate(BottomBarScreen.CDEAL.route) {

View File

@ -1,189 +0,0 @@
package com.example.testapp.screensMobile
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
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.navigation.NavController
import com.example.testapp.designElem.Btn
import com.example.testapp.designElem.SharedViewModel
import com.example.testapp.designElem.btnConfig
import com.example.testapp.graphs.AuthScreen
import com.example.testapp.graphs.Graph
import com.example.testapp.room.database.CryptoDealDb
import com.example.testapp.room.models.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
fun isValidEmail(email: String): Boolean {
val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex()
return email.matches(emailRegex)
}
@Composable
fun EntryScreen(navController: NavController,
modifier: Modifier = Modifier,
sharedViewModel: SharedViewModel) {
var emailValue by rememberSaveable { mutableStateOf("") }
var passwordValue by rememberSaveable { mutableStateOf("") }
val context = LocalContext.current
val users = remember { mutableStateListOf<User>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
CryptoDealDb.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
}
Box(
modifier = modifier
.fillMaxSize()
.background(color = Color.White)
) {
Column(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 40.dp)
) {
Text(
text = "Sign On",
color = Color(0xff0b1f33),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Medium),
modifier = Modifier
.fillMaxSize())
}
Column(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp, y = 278.dp)
.padding(start = 5.dp, end = 5.dp)
) {
TextField(
value = emailValue,
onValueChange = { emailValue = it },
label = {
Text(
text = "Email",
color = Color(0xff66727f),
lineHeight = 1.33.em,
style = TextStyle(
fontSize = 15.sp,
letterSpacing = 0.2.sp)
)
},
placeholder = { Text("Enter email") },
textStyle = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp),
modifier = Modifier
.fillMaxWidth())
TextField(
value = passwordValue,
onValueChange = { passwordValue = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
label = {
Text(
text = "Password",
color = Color(0xff66727f),
lineHeight = 1.33.em,
style = TextStyle(
fontSize = 15.sp,
letterSpacing = 0.2.sp))
},
placeholder = { Text("Enter password") },
textStyle = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp),
modifier = Modifier
.fillMaxWidth())
}
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 602.dp)
.padding(horizontal = 5.dp,
vertical = 5.dp)
.fillMaxWidth()
) {
Btn(btnConfig = btnConfig(
onClick = {
if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) {
users.forEach { user ->
if (user.password == passwordValue && user.email == emailValue) {
sharedViewModel.setArgument(user.id.toString())
navController.navigate(route = Graph.passUserId(user.id.toString()))
}
}
}},
text = "Sign In",
color = Color(0xff85c3ff),
offsetX = 0.dp,
offsetY = 0.dp
), modifier = Modifier.fillMaxWidth())
}
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp,
y = 656.dp)
.padding(horizontal = 5.dp,
vertical = 5.dp)
.fillMaxWidth()
) {
Btn(btnConfig = btnConfig(
onClick = {
navController.navigate(route = AuthScreen.Register.route)
{
popUpTo(AuthScreen.Register.route)
}
},
text = "Sign On",
color = Color(0xff85c3f3),
offsetX = 0.dp,
offsetY = 0.dp
), modifier = Modifier.fillMaxWidth())
}
}
}

View File

@ -1,6 +1,5 @@
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
@ -18,14 +17,12 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll 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.LaunchedEffect import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember 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
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
@ -34,47 +31,27 @@ import androidx.compose.ui.text.withStyle
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.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.designElem.SharedViewModel
import com.example.testapp.room.database.CryptoDealDb
import com.example.testapp.room.models.Coin import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal import com.example.testapp.room.models.Deal
import kotlinx.coroutines.Dispatchers import com.example.testapp.viewModels.AppViewModelProvider
import kotlinx.coroutines.withContext import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.HistoryViewModel
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun History(navController: NavHostController = rememberNavController(), fun History(
@SuppressLint("ModifierParameter") modifier: Modifier = Modifier, modifier: Modifier = Modifier,
sharedViewModel: SharedViewModel navController: NavHostController = rememberNavController(),
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory)
) { ) {
val argument = sharedViewModel.argument.value val id = currentUserViewModel.user!!.id
val id = argument?.toInt() historyViewModel.setArgument(id.toString());
val context = LocalContext.current val history = remember { mutableStateOf(historyViewModel.deals) }
val deals = remember { mutableStateListOf<Deal>() } val coins = remember { mutableStateOf(historyViewModel.coins) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
CryptoDealDb.getInstance(context).dealDao().getAll().collect { data ->
deals.clear()
deals.addAll(data)
}
}
}
val coins = remember { mutableStateListOf<Coin>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
CryptoDealDb.getInstance(context).coinDao().getAll().collect { data ->
coins.clear()
coins.addAll(data)
}
}
}
var history: List<Deal> = listOf();
if (id != null) {
history = deals.filter { x -> x.buyerId == id || x.sellerId == id }
}
Column( Column(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
@ -86,8 +63,14 @@ fun History(navController: NavHostController = rememberNavController(),
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
PropertyHistory() PropertyHistory()
history.forEach { history.value?.forEach { x ->
x -> HistoryCard(deal = x, modifier = Modifier.padding( vertical = 5.dp, horizontal = 5.dp), coins = coins) coins.value?.let {
HistoryCard(
deal = x,
modifier = Modifier.padding(vertical = 5.dp, horizontal = 5.dp),
coins = it
)
}
} }
} }
} }
@ -119,23 +102,31 @@ fun HistoryCard(modifier: Modifier = Modifier, deal: Deal, coins: List<Coin>) {
.padding(all = 10.dp) .padding(all = 10.dp)
) { ) {
Text( Text(
text = "-${deal.countSell} ${coins.first{x -> x.id == deal.sellerCoinId}.shortName()}", text = "-${deal.countSell} ${
coins.first { x -> x.id == deal.sellerCoinId }.shortName()
}",
color = Color(0xfff96161), color = Color(0xfff96161),
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
Text( Text(
text = "+${deal.countBuy} ${coins.first{x -> x.id == deal.buyerCoinId}.shortName()}", text = "+${deal.countBuy} ${
coins.first { x -> x.id == deal.buyerCoinId }.shortName()
}",
color = Color(0xff5acb48), color = Color(0xff5acb48),
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
Column( Column(
verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically), verticalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterVertically),
@ -152,22 +143,31 @@ fun HistoryCard(modifier: Modifier = Modifier, deal: Deal, coins: List<Coin>) {
lineHeight = 1.25.em, lineHeight = 1.25.em,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
Text( Text(
lineHeight = 1.sp, lineHeight = 1.sp,
text = buildAnnotatedString { text = buildAnnotatedString {
withStyle(style = SpanStyle( withStyle(
color = Color(0xff1e1e1e), style = SpanStyle(
fontSize = 16.sp) color = Color(0xff1e1e1e),
) {append("Status: ")} fontSize = 16.sp
withStyle(style = SpanStyle( )
color = Color(color), ) { append("Status: ") }
fontSize = 16.sp)) {append(text)}}, withStyle(
style = SpanStyle(
color = Color(color),
fontSize = 16.sp
)
) { append(text) }
},
modifier = Modifier modifier = Modifier
.wrapContentHeight(align = Alignment.CenterVertically)) .wrapContentHeight(align = Alignment.CenterVertically)
)
} }
} }
@ -197,9 +197,11 @@ fun PropertyHistory(modifier: Modifier = Modifier) {
lineHeight = 1.14.em, lineHeight = 1.14.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium), fontWeight = FontWeight.Medium
),
modifier = Modifier modifier = Modifier
.fillMaxWidth()) .fillMaxWidth()
)
} }
} }
} }

View File

@ -11,79 +11,45 @@ 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.requiredWidth
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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.LaunchedEffect import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember 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.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
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.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.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.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.room.database.CryptoDealDb import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.room.models.Coin import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.room.models.User import com.example.testapp.viewModels.DealCreateViewModel
import com.example.testapp.room.models.WalletItem import com.example.testapp.viewModels.DealListViewModel
import kotlinx.coroutines.Dispatchers import com.example.testapp.viewModels.HistoryViewModel
import kotlinx.coroutines.withContext import com.example.testapp.viewModels.WalletViewModel
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun Wallet(navController: NavHostController = rememberNavController(), fun Wallet(
@SuppressLint("ModifierParameter") modifier: Modifier = Modifier, modifier: Modifier = Modifier,
sharedViewModel: SharedViewModel) { navController: NavHostController = rememberNavController(),
val argument = sharedViewModel.argument.value currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
val id = argument?.toInt() walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory)
val context = LocalContext.current ) {
val users = remember { mutableStateListOf<User>() } val id = currentUserViewModel.user!!.id
LaunchedEffect(Unit) { walletViewModel.setArgument(id.toString())
withContext(Dispatchers.IO) { val wallet = remember { mutableStateOf(walletViewModel.wallet) }
CryptoDealDb.getInstance(context).userDao().getAll().collect { data -> val coins = remember { mutableStateOf(walletViewModel.coins) }
users.clear()
users.addAll(data)
}
}
}
var wallet: List<WalletItem> = listOf()
val walletItem = remember { mutableStateListOf<WalletItem>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
if (id != null) {
CryptoDealDb.getInstance(context).walletItemDao().getAll().collect{ data ->
walletItem.clear()
walletItem.addAll(data)
}
}
}
}
wallet = walletItem.filter { x -> x.userId == id };
val coins = remember { mutableStateListOf<Coin>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
CryptoDealDb.getInstance(context).coinDao().getAll().collect { data ->
coins.clear()
coins.addAll(data)
}
}
}
LazyColumn( LazyColumn(
verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.Top), verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.Top),
@ -97,12 +63,14 @@ fun Wallet(navController: NavHostController = rememberNavController(),
PropertyWallet() PropertyWallet()
} }
item { item {
wallet.forEach { coin -> wallet.value?.forEach { coin ->
ListItem( coins.value?.let {
coin = coins.first{ x -> x.id == coin.coinId }, ListItem(
count = coin.count, coin = it.first { x -> x.id == coin.coinId },
modifier = Modifier.padding( vertical = 5.dp) count = coin.count,
) modifier = Modifier.padding(vertical = 5.dp)
)
}
} }
} }
} }
@ -110,15 +78,28 @@ fun Wallet(navController: NavHostController = rememberNavController(),
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun LoadScreen(navController: NavHostController = rememberNavController(), fun LoadScreen(
@SuppressLint("ModifierParameter") modifier: Modifier = Modifier, navController: NavHostController = rememberNavController(),
sharedViewModel: SharedViewModel) { @SuppressLint("ModifierParameter") modifier: Modifier = Modifier,
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealCreateViewModel: DealCreateViewModel = viewModel(factory = AppViewModelProvider.Factory),
dealListViewModel: DealListViewModel = viewModel(factory = AppViewModelProvider.Factory),
historyViewModel: HistoryViewModel = viewModel(factory = AppViewModelProvider.Factory),
walletViewModel: WalletViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
Scaffold( Scaffold(
bottomBar = { NavBar(navController = navController) }, bottomBar = { NavBar(navController = navController) },
) { ) {
Modifier Modifier
.padding(it) .padding(it)
HomeNavGraph(navController, sharedViewModel) HomeNavGraph(
navController,
currentUserViewModel,
dealCreateViewModel,
dealListViewModel,
historyViewModel,
walletViewModel
)
} }
} }
@ -147,9 +128,11 @@ fun PropertyWallet(modifier: Modifier = Modifier) {
lineHeight = 1.14.em, lineHeight = 1.14.em,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium), fontWeight = FontWeight.Medium
),
modifier = Modifier modifier = Modifier
.fillMaxWidth()) .fillMaxWidth()
)
} }
} }
} }

View File

@ -0,0 +1,226 @@
package com.example.testapp.screensMobile.authScreens
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
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.designElem.Btn
import com.example.testapp.designElem.btnConfig
import com.example.testapp.graphs.AuthScreen
import com.example.testapp.graphs.Graph
import com.example.testapp.viewModels.AppViewModelProvider
import com.example.testapp.viewModels.CurrentUserViewModel
import com.example.testapp.viewModels.EntryScreenViewModel
fun isValidEmail(email: String): Boolean {
val emailRegex = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+".toRegex()
return email.matches(emailRegex)
}
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnrememberedMutableState")
@Composable
fun EntryScreen(
navController: NavController,
modifier: Modifier = Modifier,
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
entryScreenViewModel: EntryScreenViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
var emailValue by rememberSaveable { mutableStateOf("") }
var passwordValue by rememberSaveable { mutableStateOf("") }
entryScreenViewModel.setupList()
val users = mutableStateOf(entryScreenViewModel.userList)
val argument = currentUserViewModel.argument.value
var passwordVisibility by rememberSaveable { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
Box(
modifier = modifier
.fillMaxSize()
.background(color = Color.White)
) {
Column(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 40.dp
)
) {
Text(
text = "Sign On",
color = Color(0xff0b1f33),
textAlign = TextAlign.Center,
style = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Medium
),
modifier = Modifier
.fillMaxSize()
)
}
Column(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(x = 0.dp, y = 278.dp)
.padding(start = 5.dp, end = 5.dp)
) {
TextField(
value = emailValue,
onValueChange = { emailValue = it },
label = {
Text(
text = "Email",
color = Color(0xff66727f),
lineHeight = 1.33.em,
style = TextStyle(
fontSize = 15.sp,
letterSpacing = 0.2.sp
)
)
},
placeholder = { Text("Enter email") },
textStyle = TextStyle(
fontSize = 16.sp,
letterSpacing = 0.1.sp
),
modifier = Modifier
.fillMaxWidth()
)
TextField(
value = passwordValue,
onValueChange = { passwordValue = it },
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.White,
unfocusedContainerColor = Color.White,
disabledContainerColor = Color.White,
),
modifier = modifier
.fillMaxWidth()
.shadow(shape = RoundedCornerShape(40.dp), elevation = 5.dp)
.clip(shape = RoundedCornerShape(40.dp)),
label = { Text("Password") },
singleLine = true,
placeholder = { Text("Enter password") },
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
val image = if (passwordVisibility)
Icons.Filled.Visibility
else Icons.Filled.VisibilityOff
val description =
if (passwordVisibility) "Hide password" else "Show password"
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
Icon(imageVector = image, description)
}
})
}
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 602.dp
)
.padding(
horizontal = 5.dp,
vertical = 5.dp
)
.fillMaxWidth()
) {
Btn(
btnConfig = btnConfig(
onClick = {
if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) {
users.value.forEach { user ->
if (user.password == passwordValue && user.email == emailValue) {
currentUserViewModel.setArgument(user.id.toString())
navController.navigate(route = Graph.passUserId(user.id.toString()))
}
}
}
},
text = "Sign In",
color = Color(0xff85c3ff),
offsetX = 0.dp,
offsetY = 0.dp
), modifier = Modifier.fillMaxWidth()
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.align(alignment = Alignment.TopStart)
.offset(
x = 0.dp,
y = 656.dp
)
.padding(
horizontal = 5.dp,
vertical = 5.dp
)
.fillMaxWidth()
) {
Btn(
btnConfig = btnConfig(
onClick = {
navController.navigate(route = AuthScreen.Register.route)
{
popUpTo(AuthScreen.Register.route)
}
},
text = "Sign On",
color = Color(0xff85c3f3),
offsetX = 0.dp,
offsetY = 0.dp
), modifier = Modifier.fillMaxWidth()
)
}
}
}

View File

@ -1,5 +1,7 @@
package com.example.testapp.screensMobile package com.example.testapp.screensMobile.authScreens
import android.annotation.SuppressLint
import android.util.Log
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
@ -18,18 +20,15 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue 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.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
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
@ -37,34 +36,32 @@ 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.navigation.NavController import androidx.navigation.NavController
import com.example.testapp.designElem.SharedViewModel
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.database.CryptoDealDb
import com.example.testapp.room.models.User import com.example.testapp.room.models.User
import kotlinx.coroutines.CoroutineScope import com.example.testapp.viewModels.CurrentUserViewModel
import kotlinx.coroutines.Dispatchers import com.example.testapp.viewModels.RegistrationScreenViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun RegisterScreen(navController: NavController, fun RegisterScreen(
modifier: Modifier = Modifier, navController: NavController,
sharedViewModel: SharedViewModel) { modifier: Modifier = Modifier,
currentUserViewModel: CurrentUserViewModel,
registrationScreenViewModel: RegistrationScreenViewModel
) {
var emailValue by rememberSaveable { mutableStateOf("") } var emailValue by rememberSaveable { mutableStateOf("") }
var passwordValue by rememberSaveable { mutableStateOf("") } var passwordValue by rememberSaveable { mutableStateOf("") }
var passwordConfirmValue by rememberSaveable { mutableStateOf("") } var passwordConfirmValue by rememberSaveable { mutableStateOf("") }
val context = LocalContext.current registrationScreenViewModel.setUserList()
val users = remember { mutableStateListOf<User>() } val users = mutableStateOf<List<User>>(emptyList())
LaunchedEffect(Unit) { registrationScreenViewModel.users.observeForever { userList ->
withContext(Dispatchers.IO) { users.value = userList
CryptoDealDb.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
} }
val coroutineScope = rememberCoroutineScope()
Box( Box(
modifier = modifier modifier = modifier
@ -75,8 +72,10 @@ fun RegisterScreen(navController: NavController,
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top), verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.offset(x = 0.dp, .offset(
y = 40.dp) x = 0.dp,
y = 40.dp
)
) { ) {
Text( Text(
text = "Sign On", text = "Sign On",
@ -95,8 +94,10 @@ fun RegisterScreen(navController: NavController,
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.padding(start = 5.dp, end = 5.dp) .padding(start = 5.dp, end = 5.dp)
.offset(x = 0.dp, .offset(
y = 232.dp) x = 0.dp,
y = 232.dp
)
) { ) {
TextField( TextField(
value = emailValue, value = emailValue,
@ -108,14 +109,18 @@ fun RegisterScreen(navController: NavController,
lineHeight = 1.33.em, lineHeight = 1.33.em,
style = TextStyle( style = TextStyle(
fontSize = 15.sp, fontSize = 15.sp,
letterSpacing = 0.2.sp)) letterSpacing = 0.2.sp
)
)
}, },
placeholder = { Text("Enter email") }, placeholder = { Text("Enter email") },
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.fillMaxWidth()) .fillMaxWidth()
)
TextField( TextField(
value = passwordValue, value = passwordValue,
onValueChange = { passwordValue = it }, onValueChange = { passwordValue = it },
@ -126,14 +131,18 @@ fun RegisterScreen(navController: NavController,
lineHeight = 1.33.em, lineHeight = 1.33.em,
style = TextStyle( style = TextStyle(
fontSize = 15.sp, fontSize = 15.sp,
letterSpacing = 0.2.sp)) letterSpacing = 0.2.sp
)
)
}, },
placeholder = { Text("Enter password") }, placeholder = { Text("Enter password") },
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.fillMaxWidth()) .fillMaxWidth()
)
TextField( TextField(
value = passwordConfirmValue, value = passwordConfirmValue,
onValueChange = { passwordConfirmValue = it }, onValueChange = { passwordConfirmValue = it },
@ -144,40 +153,49 @@ fun RegisterScreen(navController: NavController,
lineHeight = 1.33.em, lineHeight = 1.33.em,
style = TextStyle( style = TextStyle(
fontSize = 15.sp, fontSize = 15.sp,
letterSpacing = 0.2.sp)) letterSpacing = 0.2.sp
)
)
}, },
placeholder = { Text("Confirm password") }, placeholder = { Text("Confirm password") },
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
letterSpacing = 0.1.sp), letterSpacing = 0.1.sp
),
modifier = Modifier modifier = Modifier
.fillMaxWidth()) .fillMaxWidth()
)
} }
TextButton( TextButton(
onClick = { onClick = {
var isExist = false; var isExist = false;
if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) { if (passwordValue.isNotEmpty() && isValidEmail(emailValue)) {
users.forEach { user -> users.value.forEach { user ->
if (user.email == emailValue) { if (user.email == emailValue) {
Log.d("User already exist. User id: ", user.id.toString())
isExist = true isExist = true
} }
} }
if (!isExist) { if (!isExist) {
val newUser = User(null, emailValue, passwordValue) val newUser = User(null, emailValue, passwordValue)
CoroutineScope(Dispatchers.IO).launch { coroutineScope.launch {
CryptoDealDb.getInstance(context).userDao().insert(newUser) val insertResult = async {
CryptoDealDb.getInstance(context).userDao().getAll() registrationScreenViewModel.insert(newUser)
.collect { data -> }
data.forEach { user ->
if ((user.password == passwordValue) && (user.email == emailValue)) { insertResult.await()
withContext(Dispatchers.Main) {
sharedViewModel.setArgument(user.id.toString()) registrationScreenViewModel.setUserList()
navController.navigate(route = Graph.passUserId(user.id.toString())) registrationScreenViewModel.users.observeForever { userList ->
} users.value = userList
} Log.println(Log.ASSERT, "UsersList", users.value.toString())
users.value.forEach { user ->
if (user.password == passwordValue && user.email == emailValue) {
currentUserViewModel.setArgument(user.id.toString())
navController.navigate(route = Graph.passUserId(user.id.toString()))
} }
} }
}
} }
} }
} }
@ -185,8 +203,10 @@ fun RegisterScreen(navController: NavController,
colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent),
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.offset(x = 0.dp, .offset(
y = 656.dp) x = 0.dp,
y = 656.dp
)
) { ) {
Column( Column(
verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.Top) verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.Top)
@ -206,8 +226,10 @@ fun RegisterScreen(navController: NavController,
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.TopStart) .align(alignment = Alignment.TopStart)
.fillMaxWidth() .fillMaxWidth()
.offset(x = 0.dp, .offset(
y = 602.dp) x = 0.dp,
y = 602.dp
)
) { ) {
Row( Row(
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally),
@ -220,7 +242,9 @@ fun RegisterScreen(navController: NavController,
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
} }
} }
} }
@ -240,8 +264,10 @@ fun Property1Primary(modifier: Modifier = Modifier) {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.align(alignment = Alignment.Center) .align(alignment = Alignment.Center)
.offset(x = 0.dp, .offset(
y = 0.dp) x = 0.dp,
y = 0.dp
)
) { ) {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@ -253,7 +279,9 @@ fun Property1Primary(modifier: Modifier = Modifier) {
style = TextStyle( style = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
letterSpacing = 0.1.sp)) letterSpacing = 0.1.sp
)
)
} }
} }
} }

View File

@ -0,0 +1,49 @@
package com.example.testapp.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.testapp.CryptoDealApplication
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
CurrentUserViewModel(application().container.userRepository)
}
initializer {
DealListViewModel(
application().container.dealRepository,
application().container.coinRepository
)
}
initializer {
DealCreateViewModel(
application().container.dealRepository,
application().container.coinRepository,
application().container.walletItemRepository
)
}
initializer {
EntryScreenViewModel(application().container.userRepository)
}
initializer {
HistoryViewModel(
application().container.dealRepository,
application().container.coinRepository
)
}
initializer {
RegistrationScreenViewModel(application().container.userRepository)
}
initializer {
WalletViewModel(
application().container.walletItemRepository,
application().container.coinRepository
)
}
}
}
fun CreationExtras.application(): CryptoDealApplication =
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as CryptoDealApplication)

View File

@ -0,0 +1,28 @@
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.viewModelScope
import com.example.testapp.room.models.User
import com.example.testapp.room.repository.basic.UserRepository
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class CurrentUserViewModel(private val userRepository: UserRepository) : ViewModel() {
val argument = mutableStateOf<String?>(null)
private val id = mutableStateOf<Int?>(null)
var user by mutableStateOf<User?>(null)
fun setArgument(arg: String) {
argument.value = arg
id.value = arg.toInt()
viewModelScope.launch {
user = userRepository.getById(id.value!!)
.filterNotNull()
.first()
}
}
}

View File

@ -0,0 +1,56 @@
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.viewModelScope
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.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.DealRepository
import com.example.testapp.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class DealCreateViewModel(
private val dealRepository: DealRepository,
private val coinRepository: CoinRepository,
private val walletItemRepository: WalletItemRepository
) : ViewModel() {
val argument = mutableStateOf<String?>(null)
private val user_id = mutableStateOf<Int?>(null)
private val deal_id = mutableStateOf<Int?>(null)
var deal by mutableStateOf<Deal?>(null)
var deals by mutableStateOf<List<Deal>>(emptyList())
var coins by mutableStateOf<List<Coin>>(emptyList())
var wallet by mutableStateOf<List<WalletItem>>(emptyList())
suspend fun update(deal: Deal) = dealRepository.update(deal)
suspend fun create(deal: Deal) = dealRepository.insert(deal)
fun setupLists(arg: String) {
argument.value = arg
user_id.value = arg.toInt()
viewModelScope.launch {
deals = dealRepository.getAll().first();
coins = coinRepository.getAll().first();
wallet = walletItemRepository.getUserWallet(user_id.value!!).first();
}
}
fun isEdit(): Boolean {
return deal != null;
}
fun setupEdit(id: Int) {
deal_id.value = id;
viewModelScope.launch {
deal = dealRepository.getById(id).first();
}
}
}

View File

@ -0,0 +1,32 @@
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.viewModelScope
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal
import com.example.testapp.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.DealRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class DealListViewModel(
private val dealRepository: DealRepository,
private val coinRepository: CoinRepository,
) : ViewModel() {
var deals by mutableStateOf<List<Deal>>(emptyList())
var coins by mutableStateOf<List<Coin>>(emptyList())
fun setupLists() {
viewModelScope.launch {
deals = dealRepository.getAll().first();
coins = coinRepository.getAll().first();
}
}
fun submitDeal(deal: Deal, sellerId: Int, buyerId: Int) {
dealRepository.completeDeal(deal, sellerId, buyerId)
}
}

View File

@ -0,0 +1,22 @@
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.viewModelScope
import com.example.testapp.room.models.User
import com.example.testapp.room.repository.basic.UserRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class EntryScreenViewModel(
private val userRepository: UserRepository
) : ViewModel() {
var userList by mutableStateOf<List<User>>(emptyList())
fun setupList() {
viewModelScope.launch {
userList = userRepository.getAll().first()
}
}
}

View File

@ -0,0 +1,30 @@
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.viewModelScope
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.Deal
import com.example.testapp.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.DealRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class HistoryViewModel(private val dealRepository: DealRepository,
private val coinRepository: CoinRepository) : ViewModel() {
val argument = mutableStateOf<String?>(null)
private val id = mutableStateOf<Int?>(null)
var deals by mutableStateOf<List<Deal>?>(emptyList())
var coins by mutableStateOf<List<Coin>?>(emptyList())
fun setArgument(arg: String) {
argument.value = arg
id.value = arg.toInt()
viewModelScope.launch {
deals = dealRepository.getUserDeals(id.value!!).first()
coins = coinRepository.getAll().first()
}
}
}

View File

@ -0,0 +1,25 @@
package com.example.testapp.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.testapp.room.models.User
import com.example.testapp.room.repository.basic.UserRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class RegistrationScreenViewModel(private val userRepository: UserRepository) : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> get() = _users
fun setUserList() {
viewModelScope.launch {
_users.value = userRepository.getAll().first()
}
}
suspend fun insert(user: User) {
userRepository.insert(user)
}
}

View File

@ -0,0 +1,32 @@
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.viewModelScope
import com.example.testapp.room.models.Coin
import com.example.testapp.room.models.WalletItem
import com.example.testapp.room.repository.basic.CoinRepository
import com.example.testapp.room.repository.basic.WalletItemRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
class WalletViewModel(
private val walletItemRepository: WalletItemRepository,
private val coinRepository: CoinRepository
) : ViewModel() {
val argument = mutableStateOf<String?>(null)
private val id = mutableStateOf<Int?>(null)
var wallet by mutableStateOf<List<WalletItem>?>(emptyList())
var coins by mutableStateOf<List<Coin>?>(emptyList())
fun setArgument(arg: String) {
argument.value = arg
id.value = arg.toInt()
viewModelScope.launch {
wallet = walletItemRepository.getUserWallet(id.value!!).first()
coins = coinRepository.getAll().first()
}
}
}