Feature: complete basket implementation
This commit is contained in:
parent
52d4438a41
commit
eb1eb47ce0
@ -96,7 +96,7 @@ fun CardSneaker(item: Sneaker, navController: NavHostController, basketViewModel
|
||||
if(GlobalUser.getInstance().getUser() == null){
|
||||
navController.navigate("login")
|
||||
}else{
|
||||
basketViewModel.addToBasket(BasketSneakers(GlobalUser.getInstance().getUser()?.userId!!, item.sneakerId!!))
|
||||
basketViewModel.addToBasket(BasketSneakers(GlobalUser.getInstance().getUser()?.userId!!, item.sneakerId!!, 1))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
|
@ -11,7 +11,14 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -21,6 +28,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.example.android_programming.R
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.example.android_programming.composeui.Screens.OrderScreen
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -12,10 +13,17 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@ -33,8 +41,11 @@ import com.example.android_programming.vmodel.AppViewModelProvider
|
||||
import com.example.android_programming.vmodel.BasketViewModel
|
||||
import com.example.android_programming.vmodel.OrderViewModel
|
||||
|
||||
@SuppressLint("UnrememberedMutableState")
|
||||
@Composable
|
||||
fun CardSneakerLike(item: Sneaker, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||
val userId = GlobalUser.getInstance().getUser()?.userId!!
|
||||
val quantityState by basketViewModel.getQuantityState(userId, item.sneakerId!!).collectAsState()
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -63,6 +74,7 @@ fun CardSneakerLike(item: Sneaker, basketViewModel: BasketViewModel = viewModel(
|
||||
Text(text = "${item.price} USD", color = Color.Red, fontSize = 16.sp)
|
||||
}
|
||||
|
||||
Column {
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = colorResource(id = R.color.figma_blue),
|
||||
@ -77,4 +89,17 @@ fun CardSneakerLike(item: Sneaker, basketViewModel: BasketViewModel = viewModel(
|
||||
Icon(imageVector = Icons.Default.Delete, contentDescription = "delete")
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
Row {
|
||||
IconButton(onClick = { basketViewModel.decrementQuantity(userId ,item.sneakerId!!) }) {
|
||||
Icon(Icons.Default.KeyboardArrowLeft, contentDescription = "Decrease Quantity")
|
||||
}
|
||||
Text("$quantityState")
|
||||
IconButton(onClick = { basketViewModel.incrementQuantity(userId, item.sneakerId!!) }) {
|
||||
Icon(Icons.Default.KeyboardArrowRight, contentDescription = "Increase Quantity")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,16 +9,21 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.android_programming.GlobalUser
|
||||
import com.example.android_programming.R
|
||||
import com.example.android_programming.vmodel.OrderViewModel
|
||||
|
||||
@Composable
|
||||
fun SubTotal(orderViewModel: OrderViewModel) {
|
||||
val userId = GlobalUser.getInstance().getUser()?.userId!!
|
||||
orderViewModel.updateSubTotal(userId)
|
||||
val subTotal = orderViewModel.subTotal.value
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
@ -41,7 +46,7 @@ fun SubTotal(orderViewModel: OrderViewModel) {
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalArrangement = Arrangement.End
|
||||
){
|
||||
Text(text = "${orderViewModel.getSubTotal()} $", fontSize = 15.sp)
|
||||
Text(text = "$subTotal $", fontSize = 15.sp)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
@ -60,7 +65,7 @@ fun SubTotal(orderViewModel: OrderViewModel) {
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalArrangement = Arrangement.End
|
||||
){
|
||||
Text(text = "${"%.2f".format(orderViewModel.getSubTotal() * 0.05)} $", fontSize = 15.sp)
|
||||
Text(text = "${"%.2f".format(subTotal * 0.05)} $", fontSize = 15.sp)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
@ -79,7 +84,7 @@ fun SubTotal(orderViewModel: OrderViewModel) {
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalArrangement = Arrangement.End
|
||||
){
|
||||
Text(text = "${"%.2f".format(orderViewModel.getSubTotal() + orderViewModel.getSubTotal() * 0.05)} $", fontSize = 15.sp)
|
||||
Text(text = "${"%.2f".format(subTotal + subTotal * 0.05)} $", fontSize = 15.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,4 +28,20 @@ interface BasketDao {
|
||||
|
||||
@Query("DELETE FROM 'BasketSneakers' WHERE basketId = :basketId AND sneakerId = :sneakerId")
|
||||
suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int)
|
||||
|
||||
@Query("UPDATE 'BasketSneakers' SET quantity = :quantity WHERE basketId = :basketId AND sneakerId = :sneakerId")
|
||||
suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int)
|
||||
|
||||
@Query("UPDATE 'BasketSneakers' SET quantity = quantity + 1 WHERE basketId = :basketId AND sneakerId = :sneakerId")
|
||||
suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int)
|
||||
|
||||
@Query("UPDATE 'BasketSneakers' SET quantity = quantity - 1 WHERE basketId = :basketId AND sneakerId = :sneakerId")
|
||||
suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int)
|
||||
|
||||
@Query("SELECT quantity FROM 'BasketSneakers' WHERE basketId = :basketId AND sneakerId = :sneakerId")
|
||||
suspend fun getQuantity(basketId: Int, sneakerId: Int): Int?
|
||||
@Query("SELECT * FROM 'BasketSneakers' WHERE basketId = :basketId AND sneakerId = :sneakerId")
|
||||
suspend fun getSneaker(basketId: Int, sneakerId: Int): BasketSneakers?
|
||||
@Query("SELECT SUM(price * quantity) FROM 'BasketSneakers' bs JOIN 'Sneaker' s ON bs.sneakerId = s.sneakerId WHERE bs.basketId = :userId")
|
||||
suspend fun getTotalPriceForUser(userId: Int): Double?
|
||||
}
|
@ -7,4 +7,5 @@ import androidx.room.PrimaryKey
|
||||
class BasketSneakers (
|
||||
val basketId: Int,
|
||||
val sneakerId: Int,
|
||||
val quantity: Int
|
||||
)
|
@ -5,5 +5,6 @@ import androidx.room.Entity
|
||||
@Entity(primaryKeys = ["orderId", "sneakerId"])
|
||||
data class OrderSneaker(
|
||||
val orderId: Int,
|
||||
val sneakerId: Int
|
||||
val sneakerId: Int,
|
||||
val quantity: Int
|
||||
)
|
@ -9,8 +9,14 @@ import kotlinx.coroutines.flow.Flow
|
||||
class BasketRepoImpl(private val basketDao: BasketDao): BasketRepository {
|
||||
override suspend fun createBasket(basket: Basket): Long = basketDao.createBasket(basket)
|
||||
override suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int) = basketDao.removeSneakerFromBasket(basketId, sneakerId)
|
||||
override suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int) = basketDao.updateSneakerQuantity(basketId, sneakerId, quantity)
|
||||
override suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int) = basketDao.incrementSneakerQuantity(basketId, sneakerId)
|
||||
override suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int) = basketDao.decrementSneakerQuantity(basketId, sneakerId)
|
||||
override suspend fun insertBasketSneaker(basketSneaker: BasketSneakers) = basketDao.insertBasketSneaker(basketSneaker)
|
||||
override fun getBasketWithSneakers(id: Int): Flow<BasketWithSneakers> = basketDao.getBasketWithSneakers(id)
|
||||
override fun getAllBasket(): Flow<List<Basket>> = basketDao.getAllBasket()
|
||||
override suspend fun delete(basket: Basket) = basketDao.delete(basket)
|
||||
override suspend fun getQuantity(basketId: Int, sneakerId: Int): Int? = basketDao.getQuantity(basketId, sneakerId)
|
||||
override suspend fun getSneaker(basketId: Int, sneakerId: Int): BasketSneakers? = basketDao.getSneaker(basketId, sneakerId)
|
||||
override suspend fun getTotalPriceForUser(userId: Int): Double? = basketDao.getTotalPriceForUser(userId)
|
||||
}
|
@ -15,4 +15,10 @@ interface BasketRepository {
|
||||
suspend fun delete(basket: Basket)
|
||||
suspend fun createBasket(basket: Basket):Long
|
||||
suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int)
|
||||
suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int)
|
||||
suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int)
|
||||
suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int)
|
||||
suspend fun getQuantity(basketId: Int, sneakerId: Int): Int?
|
||||
suspend fun getSneaker(basketId: Int, sneakerId: Int): BasketSneakers?
|
||||
suspend fun getTotalPriceForUser(userId: Int): Double?
|
||||
}
|
@ -15,7 +15,7 @@ object AppViewModelProvider {
|
||||
UserViewModel(app().container.userRepo)
|
||||
}
|
||||
initializer {
|
||||
OrderViewModel(app().container.orderRepo)
|
||||
OrderViewModel(app().container.orderRepo, app().container.basketRepo)
|
||||
}
|
||||
initializer {
|
||||
BasketViewModel(app().container.basketRepo)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.example.android_programming.vmodel
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.android_programming.model.Basket
|
||||
@ -9,13 +11,39 @@ import com.example.android_programming.model.BasketWithSneakers
|
||||
import com.example.android_programming.model.Sneaker
|
||||
import com.example.android_programming.repository.BasketRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class BasketViewModel(private val basketRepository: BasketRepository): ViewModel() {
|
||||
|
||||
private val _quantityStateMap = mutableMapOf<Int, MutableStateFlow<Int>>()
|
||||
|
||||
fun getQuantityState(basketId: Int, sneakerId: Int): StateFlow<Int> {
|
||||
val quantityStateFlow = _quantityStateMap.getOrPut(sneakerId) {
|
||||
MutableStateFlow(0)
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
val quantityFromDb = basketRepository.getQuantity(basketId, sneakerId)
|
||||
quantityFromDb?.let { quantityStateFlow.value = it }
|
||||
}
|
||||
|
||||
return quantityStateFlow
|
||||
}
|
||||
|
||||
suspend fun isSneakerInBasket(basketId: Int, sneakerId: Int): Boolean {
|
||||
return basketRepository.getSneaker(basketId, sneakerId) != null
|
||||
}
|
||||
fun addToBasket(basketSneakers: BasketSneakers) = viewModelScope.launch {
|
||||
val isSneakerInBasket = isSneakerInBasket(basketSneakers.basketId, basketSneakers.sneakerId)
|
||||
|
||||
if (isSneakerInBasket) {
|
||||
incrementQuantity(basketSneakers.basketId, basketSneakers.sneakerId)
|
||||
} else {
|
||||
basketRepository.insertBasketSneaker(basketSneakers)
|
||||
}
|
||||
}
|
||||
|
||||
fun getBasketSneakers(id: Int): Flow<BasketWithSneakers> {
|
||||
return basketRepository.getBasketWithSneakers(id)
|
||||
@ -24,4 +52,24 @@ class BasketViewModel(private val basketRepository: BasketRepository): ViewModel
|
||||
fun deleteSneakerFromBasket(basketId: Int, sneakerId: Int) = viewModelScope.launch {
|
||||
basketRepository.removeSneakerFromBasket(basketId, sneakerId)
|
||||
}
|
||||
|
||||
fun incrementQuantity(basketId: Int, sneakerId: Int) {
|
||||
val currentQuantity = _quantityStateMap[sneakerId]?.value ?: 1
|
||||
_quantityStateMap[sneakerId]?.value = currentQuantity + 1
|
||||
|
||||
viewModelScope.launch {
|
||||
basketRepository.incrementSneakerQuantity(basketId, sneakerId)
|
||||
}
|
||||
}
|
||||
|
||||
fun decrementQuantity(basketId: Int, sneakerId: Int) {
|
||||
val currentQuantity = _quantityStateMap[sneakerId]?.value ?: 1
|
||||
if (currentQuantity > 1) {
|
||||
_quantityStateMap[sneakerId]?.value = currentQuantity - 1
|
||||
|
||||
viewModelScope.launch {
|
||||
basketRepository.decrementSneakerQuantity(basketId, sneakerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.example.android_programming.vmodel
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
@ -23,12 +24,14 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Date
|
||||
|
||||
class OrderViewModel(private val orderRepository: OrderRepository) : ViewModel() {
|
||||
class OrderViewModel(private val orderRepository: OrderRepository, private val basketRepository: BasketRepository) : ViewModel() {
|
||||
|
||||
var city = mutableStateOf("")
|
||||
val street = mutableStateOf("")
|
||||
val house = mutableStateOf("")
|
||||
private val _selectedItems = MutableLiveData<List<Sneaker>>()
|
||||
private val _subTotal = mutableStateOf(0.0)
|
||||
val subTotal: State<Double> get() = _subTotal
|
||||
val selectedItems: LiveData<List<Sneaker>> get() = _selectedItems
|
||||
|
||||
fun updateSelectedItems(items: List<Sneaker>) {
|
||||
@ -48,29 +51,40 @@ class OrderViewModel(private val orderRepository: OrderRepository) : ViewModel()
|
||||
}
|
||||
|
||||
fun createOrder() = viewModelScope.launch {
|
||||
val userId = GlobalUser.getInstance().getUser()?.userId!!
|
||||
val order = Order(
|
||||
date = Date().time,
|
||||
city = city.value,
|
||||
street = street.value,
|
||||
house = house.value,
|
||||
subtotal = getSubTotal(),
|
||||
taxes = "%.2f".format(getSubTotal() * 0.05).toDouble(),
|
||||
total = "%.2f".format(getSubTotal() * 0.05 + getSubTotal()).toDouble(),
|
||||
subtotal = getSubTotal(userId),
|
||||
taxes = "%.2f".format(getSubTotal(userId) * 0.05).toDouble(),
|
||||
total = "%.2f".format(getSubTotal(userId) * 0.05 + getSubTotal(userId)).toDouble(),
|
||||
creatorUserId = GlobalUser.getInstance().getUser()?.userId!!
|
||||
)
|
||||
|
||||
val orderId = orderRepository.createOrder(order)
|
||||
|
||||
for (sneaker in selectedItems.value.orEmpty()) {
|
||||
val orderSneaker = OrderSneaker( orderId.toInt(), sneaker.sneakerId!!)
|
||||
val userId = GlobalUser.getInstance().getUser()?.userId!!
|
||||
val orderSneaker = basketRepository.getQuantity(userId, sneaker.sneakerId!!)
|
||||
?.let { OrderSneaker( orderId.toInt(), sneaker.sneakerId!!, it) }
|
||||
if (orderSneaker != null) {
|
||||
orderRepository.insertOrderSneaker(orderSneaker)
|
||||
}
|
||||
}
|
||||
city.value = ""
|
||||
street.value = ""
|
||||
house.value = ""
|
||||
}
|
||||
|
||||
fun getSubTotal(): Double {
|
||||
return 0.0
|
||||
fun updateSubTotal(userId: Int) {
|
||||
viewModelScope.launch {
|
||||
_subTotal.value = getSubTotal(userId)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSubTotal(userId: Int): Double {
|
||||
return basketRepository.getTotalPriceForUser(userId) ?: 0.0
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user