Skip to content

Instantly share code, notes, and snippets.

@thegarlynch
Last active June 23, 2020 20:16
Show Gist options
  • Select an option

  • Save thegarlynch/2d89a736a7e0e6cb014a9b0b332f20e1 to your computer and use it in GitHub Desktop.

Select an option

Save thegarlynch/2d89a736a7e0e6cb014a9b0b332f20e1 to your computer and use it in GitHub Desktop.
Implementation of cart
import com.myapplication.domain.model.checkout.CartItem
import com.myapplication.helper.rx.ThreadConfinedBehaviorSubject
import io.reactivex.Scheduler
import java.math.BigInteger
import javax.annotation.concurrent.ThreadSafe
import javax.inject.Inject
import javax.inject.Singleton
/**
* Beware!!
*
* Cart operation must guarantees that no background execution outside of what is triggered
* by user is happening. for example : calling [Cart.add] randomly by remote synchronization
*
* If you want to implement remote synchronization, it is advised to implement [CartStorage]
* and used it only as initial syncing and save mechanism
*
* @see [CartStorage.loadCart] and [CartStorage.observeCartChanges]
*/
@ThreadSafe
@Singleton
class Cart @Inject constructor(cartStorage : CartStorage){
private val cartSubject = ThreadConfinedBehaviorSubject.createDefault<List<CartItem>>(emptyList())
private val cartInternalObserver = cartSubject.expose()
.distinctUntilChanged()
private val totalPriceObservable = cartInternalObserver
.map { it.totalPrice }
private val badgeObserver = cartInternalObserver
.map { it.size }
init {
val initialCart = cartStorage.loadCart()
cartSubject.update { onNext(initialCart) }
/**
* make cartSubject be source of truth for what cart contains of
*/
cartStorage.observeCartChanges(cartInternalObserver.share())
}
fun observeOn(scheduler : Scheduler) = cartInternalObserver.share().observeOn(scheduler)!!
fun observeBadgeCount() = badgeObserver.share()!!
fun observeTotalPrice() = totalPriceObservable.share()!!
fun add(item : CartItem) {
cartSubject.update { onNext(value!! + item) }
}
fun changeItem(newItem : CartItem){
cartSubject.update {
val cart = value!!
val oldItem = cart.first { it.id == newItem.id }
cart - oldItem + newItem
}
}
fun removeItem(item : CartItem){
cartSubject.update {
val cart = value!!
cart - item
}
}
}
val List<CartItem>.totalPrice : BigInteger
get() {
return fold(BigInteger.ZERO){ acc, cartItem ->
acc + cartItem.price
}
}
import android.os.Bundle
import android.view.View
import com.myapplication.R
import com.myapplication.domain.model.checkout.CartItem
import com.myapplication.domain.model.checkout.cart.Cart
import com.myapplication.domain.model.checkout.cart.totalPrice
import com.myapplication.helper.date.DateFormat
import com.myapplication.helper.fragment.DisposeOn
import com.myapplication.helper.misc.PriceUtil
import com.myapplication.helper.misc.dp
import com.myapplication.helper.recyclerview.vertical
import com.myapplication.presenter.base.AbstractFragment
import com.myapplication.presenter.payment.checkout.adapter.CheckoutAdapter
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.Maybe
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.checkout.*
import kotlinx.android.synthetic.main.pricetotal_below.*
import org.threeten.bp.LocalDate
import javax.inject.Inject
@AndroidEntryPoint
class CheckoutFragment : AbstractFragment(R.layout.checkout) {
@Inject lateinit var cart : Cart
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkout_products.vertical(10.dp)
val adapter = CheckoutAdapter(this)
checkout_products.adapter = adapter
cart.observeOn(AndroidSchedulers.mainThread()).subscribe {
checkout_total_price.text = PriceUtil.toRupiah(it.totalPrice)
adapter.submitList(it)
}.autoDispose(DisposeOn.VIEW_DESTROYED)
cart_button.setOnClickListener {
val action = CheckoutFragmentDirections.pay()
navController.navigate(action)
}
checkout_date.text = requireContext().getString(R.string.checkout_date, DateFormat.defaultDate(LocalDate.now()))
}
inner class CartUpdateListener : CheckoutAdapter.CartUpdateListener{
override fun observeItemRemoved(itemObserver: Maybe<out CartItem>) {
itemObserver.subscribe {
cart.removeItem(it)
}.autoDispose(DisposeOn.VIEW_DESTROYED)
}
override fun observeItemUpdate(itemObserver: Maybe<out CartItem>) {
itemObserver.subscribe {
cart.changeItem(it)
}.autoDispose(DisposeOn.VIEW_DESTROYED)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment