Проблема со счетчиком во фрагменте CartFragment
При изменений количества товара увеличивается и его цена, но когда в корзине нажимаешь на товар чтобы посмотреть на товар подробнее а потом выходишь обратно и меняешь количество товара то не меняется цена, искал долго лазил по разным форумам не нашел решения и сам не смог додуматся, помогите чем сможете
CartFragment
class CartFragment : Fragment() {
private var _binding: FragmentCartBinding? = null
private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
requestProducts()
}
}
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding
lateinit var cartViewModel: CartViewModel
var adapter: CartRecyclerAdapter? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
cartViewModel =
ViewModelProvider(this)[CartViewModel::class.java]
(activity as? AppCompatActivityWithLoading)?.setViewModel(cartViewModel)
_binding = FragmentCartBinding.inflate(inflater, container, false)
val root: View = binding!!.root
binding?.bottomBar?.isVisible = false
if (context?.let { User.isLogged(it) } == false){
binding?.loginButton?.isVisible = true
binding?.noDataView?.isVisible = true
} else {
binding?.loginButton?.isVisible = false
binding?.noDataView?.isVisible = false
requestProducts()
}
adapter = context?.let { CartRecyclerAdapter(it) }
adapter?.onProductClickListener = {
val product = MenuProduct(
it.product,
it.name,
null,
variant = MenuProduct.ProductVariant(it.v_id, it.price, null, null),
image = it.image?.thumbnail,
rating = MenuProduct.Rating(0f,0)
)
val bundle = bundleOf(DetailedProductFragment.MENU_PRODUCT to product)
findNavController().navigate(R.id.action_detailedProduct, bundle)
}
adapter?.onRemoveListener = {
deleteProduct(it)
}
adapter?.onWarnMaxCount = {
AlertDialog.Builder(context)
.setMessage(getString(R.string.sorry_out_of_stock))
.setCancelable(true)
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
dialog.dismiss()
}.create().show()
}
adapter?.onUpdateListener = {it, callback ->
cartViewModel.updateAmount(it){
if (it){
configureBottomBar()
}
callback(it)
}
}
binding?.cartRecycler?.adapter = adapter
cartViewModel.cartData.observe(this){
adapter?.differ?.submitList(it)
configureBottomBar()
(activity as? MainActivity)?.setBadge(cartViewModel.getCartCount)
}
val resultThank = findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Boolean>(
ThankYouFragment.SUCCESS
)?.value
if (resultThank == true){
findNavController().currentBackStackEntry?.savedStateHandle?.set(ThankYouFragment.SUCCESS, null)
findNavController().navigate(R.id.action_myOrders)
}
val result = findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Boolean>(
CheckoutFragment.ORDER_SUCCESS
)?.value
if (result == true){
findNavController().currentBackStackEntry?.savedStateHandle?.set(CheckoutFragment.ORDER_SUCCESS, null)
cartViewModel.cleanCart()
requestProducts()
findNavController().navigate(R.id.action_thankyou)
}
binding?.checkoutButton?.setOnClickListener {
val arr = arrayListOf<Map<String, Number>>()
cartViewModel.cartData.value?.forEach {
arr.addAll(it.products.map { hashMapOf("variant" to it.v_id, "count" to it.quantity, "price" to (it.price*it.quantity.toDouble())) })
}
val bundle = bundleOf(CART_PRODUCTS to arr)
findNavController().navigate(R.id.action_checkout, bundle)
}
binding?.buttonRetry?.setOnClickListener {
requestProducts()
}
binding?.loginButton?.setOnClickListener {
launcher.launch(Intent(context, LoginActivity::class.java))
}
return root
}
private fun requestProducts(){
productLoading(true)
cartViewModel.getCartProducts {
productLoading(false, it)
adapter?.differ?.submitList(it)
}
}
private fun productLoading(isLoading: Boolean, data: List<Any>? = null){
binding?.cartRecycler?.isVisible = !isLoading && data?.isNotEmpty() == true
binding?.errorMessage?.isVisible = !isLoading && data == null
binding?.noDataView?.isVisible = !isLoading && data?.isEmpty() == true
binding?.loginButton?.isVisible = false
binding?.shimmerViewContainer?.isVisible = isLoading
}
private fun configureBottomBar() {
val total = cartViewModel.cartTotal
binding?.bottomBar?.isVisible = total != null
binding?.mainPrice?.text = PriceFormatter.getPrice(total)
(activity as? MainActivity)?.setBadge(cartViewModel.getCartCount)
}
private fun deleteProduct(pId: Int) {
val builder = AlertDialog.Builder(context)
builder.setMessage(getString(R.string.are_you_sure_delete))
.setCancelable(false)
.setPositiveButton(getString(R.string.yes)) { _, _ ->
// Delete selected note from database
cartViewModel.removeProduct(pId)
}
.setNegativeButton(getString(R.string.no)) { dialog, _ ->
// Dismiss the dialog
dialog.dismiss()
}
val alert = builder.create()
alert.show()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
// override fun onResume() {
// super.onResume()
// requestProducts()
// }
companion object {
const val CART_PRODUCTS = "cartProducts"
}
}
CartRepository
class CartRepository {
suspend fun getCartCount(): Int {
val request = Network.apiClient.getCartCount()
if (request.failed){
Log.e("mylog", request.exception?.stackTraceToString() ?: "Errrror")
return 0
}
if (!request.isSuccessful){
return 0
}
return request.body.data ?: 0
}
suspend fun getCartProducts(): List<CartItem>? {
val request = Network.apiClient.getCartProducts()
if (request.failed){
Log.e("mylog", request.exception?.stackTraceToString() ?: "Errrror")
return null
}
if (!request.isSuccessful){
return null
}
return request.body.data
}
suspend fun removeFromCart(variantId: Int): Boolean {
val request = Network.apiClient.removeFromCart(variantId)
if (request.failed){
Log.e("mylog", request.exception?.stackTraceToString() ?: "Errrror")
return false
}
if (!request.isSuccessful){
return false
}
return request.body.isSuccess
}
suspend fun updateAmount(variantId: Int, amount: Number): Boolean {
val request = Network.apiClient.updateCartProduct(variantId, amount)
if (request.failed){
Log.e("mylog", request.exception?.stackTraceToString() ?: "Errrror")
return false
}
if (!request.isSuccessful){
return false
}
return request.body.isSuccess
}
}
CartViewModel
class CartViewModel : ViewModelWithLoading() {
val getCartCount: Int get() {
var count = 0
_cartData.value?.forEach { it.products.forEach {
count += if (it.isFloat) 1 else it.quantity.toInt()
} }
return count
}
private val cartRepository = CartRepository()
private val _cartData = MutableLiveData<List<CartItem>?>()
val cartData: LiveData<List<CartItem>?> = _cartData
val cartTotal: Double?
get(){
if (_cartData.value == null)
return null
var total = 0.0
_cartData.value?.forEach {
it.products.forEach {
total += it.price * it.quantity.toDouble()
}
}
return if (total == 0.0) null else total
}
fun getCartProducts(callback: (List<CartItem>?) -> Unit) {
viewModelScope.launch {
val response = cartRepository.getCartProducts()
_cartData.postValue(response)
callback(response)
}
}
fun removeProduct(variantId: Int) {
startLoading()
viewModelScope.launch {
val response = cartRepository.removeFromCart(variantId)
if (response) {
val list = cartRepository.getCartProducts()
_cartData.postValue(list)
}
stopLoading()
}
}
fun updateAmount(cartProduct: CartItem.CartProduct, callback: (Boolean)->Unit) {
startLoading()
viewModelScope.launch {
val response = cartRepository.updateAmount(cartProduct.v_id, cartProduct.quantity)
callback(response)
stopLoading()
}
}
fun cleanCart() {
_cartData.postValue(null)
}
}
CartRecyclerAdapter
class CartRecyclerAdapter(val context: Context): RecyclerView.Adapter<CartRecyclerAdapter.CartItemViewHolder>(){
var onRemoveListener: ((Int)->Unit)? = null
var onUpdateListener: ((CartItem.CartProduct, (Boolean)->Unit)->Unit)? = null
var onProductClickListener: ((CartItem.CartProduct)->Unit)? = null
var onWarnMaxCount: ((CartItem.CartProduct)->Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartItemViewHolder {
val productView = LayoutInflater.from(parent.context).inflate(R.layout.cart_item,parent,false)
return CartItemViewHolder(productView)
}
private val differCallback = object : DiffUtil.ItemCallback<CartItem>(){
override fun areItemsTheSame(oldItem: CartItem, newItem: CartItem): Boolean {
return oldItem.id == newItem.id
}
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: CartItem, newItem: CartItem): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this,differCallback)
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: CartItemViewHolder, position: Int) {
val item: CartItem = differ.currentList[position]
holder.apply {
sellerTitle.text = item.market_name
if (productsRecycler.adapter == null) {
val adapter = CartProductRecyclerAdapter(context)
adapter.shippingTime = item.shipping_time
adapter.onRemoveClickListener = onRemoveListener
adapter.onUpdateListener = onUpdateListener
adapter.onProductClickListener = onProductClickListener
adapter.onWarnMaxCount = onWarnMaxCount
productsRecycler.adapter = adapter
}
(productsRecycler.adapter as? CartProductRecyclerAdapter)?.differ?.submitList(item.products)
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
class CartItemViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val sellerTitle: TextView = itemView.findViewById(R.id.seller_title)
val productsRecycler: RecyclerView = itemView.findViewById(R.id.product_recycler)
}
}
CaerProductRecyclerAdapter
class CartProductRecyclerAdapter(val context: Context) :
RecyclerView.Adapter<CartProductRecyclerAdapter.CartProductViewHolder>(){
var shippingTime: Int? = null
var onRemoveClickListener: ((Int)->Unit)? = null
var onUpdateListener: ((CartItem.CartProduct, (Boolean)->Unit)->Unit)? = null
var onProductClickListener: ((CartItem.CartProduct)->Unit)? = null
var onWarnMaxCount: ((CartItem.CartProduct)->Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartProductViewHolder {
val productView = LayoutInflater.from(parent.context).inflate(R.layout.cart_product_item,parent,false)
return CartProductViewHolder(productView)
}
private val differCallback = object : DiffUtil.ItemCallback<CartItem.CartProduct>(){
override fun areItemsTheSame(oldItem: CartItem.CartProduct, newItem: CartItem.CartProduct): Boolean {
return oldItem.id == newItem.id
}
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: CartItem.CartProduct, newItem: CartItem.CartProduct): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this,differCallback)
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: CartProductViewHolder, position: Int) {
val item = differ.currentList[position]
holder.apply {
title.text = HtmlCompat.fromHtml("<b>${item.brand ?: ""}</b> ${item.name}", HtmlCompat.FROM_HTML_MODE_LEGACY)
Picasso.get().load(item.image?.thumbnail).into(image)
setQuantityPrice(item, holder)
optionKey.isVisible = item.option != null
optionValue.isVisible = item.option != null
if (item.option != null){
optionKey.text = item.option.option.name + ": "
optionValue.text = item.option.value.name
}
divider.isVisible = (position != differ.currentList.size - 1)
}
}
private fun setQuantityPrice(item: CartItem.CartProduct, holder: CartProductRecyclerAdapter.CartProductViewHolder) {
holder.apply {
price.text = PriceFormatter.getPrice(item.price * item.quantity.toDouble())
oldPrice.paintFlags = oldPrice.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
oldPrice.text = if (item.oldPrice != null){
PriceFormatter.getPrice(item.oldPrice!! * item.quantity.toDouble())
} else {
null
}
quantity.text = "${item.quantity}"
Log.e("mlog", " ${image.height} ${dataCont.height + actionCont.height}")
val h = image.height - dataCont.height - actionCont.height
val top = if (h > 0) h else 0
actionCont.setPadding(0, top, 0, 0 )
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
inner class CartProductViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val title: TextView = itemView.findViewById(R.id.title)
val image: ImageView = itemView.findViewById(R.id.image)
val optionKey: TextView = itemView.findViewById(R.id.option_key)
val optionValue: TextView = itemView.findViewById(R.id.option_value)
val oldPrice: TextView = itemView.findViewById(R.id.old_price)
val price: TextView = itemView.findViewById(R.id.price)
val quantity: TextView = itemView.findViewById(R.id.quantity)
val increase: ImageButton = itemView.findViewById(R.id.quantity_increase)
val decrease: ImageButton = itemView.findViewById(R.id.quantity_decrease)
val remove: ImageButton = itemView.findViewById(R.id.button_remove)
val divider: View = itemView.findViewById(R.id.divider)
val dataCont: View = itemView.findViewById(R.id.data_container)
val actionCont: View = itemView.findViewById(R.id.action_container)
val shipping: TextView = itemView.findViewById(R.id.shipping)
val shippingCont: View = itemView.findViewById(R.id.shipping_cont)
init {
remove.setOnClickListener {
val item = differ.currentList[layoutPosition]
onRemoveClickListener?.invoke(item.v_id)
}
increase.setOnClickListener {
val item = differ.currentList[layoutPosition]
if (item.inc() == null){
onWarnMaxCount?.invoke(item)
return@setOnClickListener
}
setQuantityPrice(item, this)
onUpdateListener?.invoke(item){
if (!it){
item.dec()
setQuantityPrice(item, this)
}
}
}
decrease.setOnClickListener {
val item = differ.currentList[layoutPosition]
if (item.dec() == null){
onRemoveClickListener?.invoke(item.v_id)
return@setOnClickListener
}
setQuantityPrice(item, this)
onUpdateListener?.invoke(item){
if (!it){
item.inc()
setQuantityPrice(item, this)
}
}
}
itemView.setOnClickListener {
val item = differ.currentList[layoutPosition]
onProductClickListener?.invoke(item)
}
shippingCont.isVisible = shippingTime != null
shipping.text = String.format(context.getString(R.string._deliv_hours), shippingTime)
}
}
}