Advertisement
Guest User

Untitled

a guest
Jan 27th, 2020
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 7.27 KB | None | 0 0
  1. class GoodsScannerViewModel @AssistedInject constructor(
  2.     @Assisted private val orderId: String,
  3.     private val router: Router,
  4.     private val orderInteractor: OrderInteractor
  5. ) : BaseViewModel() {
  6.  
  7.     private val viewState = MutableLiveData<ViewState>().apply {
  8.         value = ViewState(
  9.             mode = ADD_MODE,
  10.             totalGoodsQty = 0,
  11.             positions = mutableListOf()
  12.         )
  13.     }
  14.  
  15.     private val coroutineScope = ViewModelCoroutineScope.create(this)
  16.  
  17.     private val verificationResultEvents = SingleLiveEvent<BarcodeVerificationResult>()
  18.  
  19.     private val barcodeSubject = PublishSubject.create<String>()
  20.     private var barcodesDisposable: Disposable = Disposables.empty()
  21.     @Volatile
  22.     private var skipBarcodes = false
  23.  
  24.     private lateinit var session: GiveOrderSession
  25.  
  26.     init {
  27.         loadViewState()
  28.     }
  29.  
  30.     private fun loadViewState() = coroutineScope.launch {
  31.         session = orderInteractor.getGiveOrderSession(orderId) ?: return@launch
  32.  
  33.         val positions = session.order.goodsForDelivery.map {
  34.             PositionState(
  35.                 id = it.id,
  36.                 name = it.name,
  37.                 totalQty = it.shippedQuantity
  38.             )
  39.         }
  40.  
  41.         viewState.postUpdateValue { viewState ->
  42.             viewState.copy(
  43.                 totalGoodsQty = positions.sumBy { it.totalQty },
  44.                 positions = positions
  45.             )
  46.         }
  47.  
  48.         barcodesDisposable = subscribeToBarcodes()
  49.     }
  50.  
  51.     private fun subscribeToBarcodes() = barcodeSubject
  52.         .skipWhile { skipBarcodes }
  53.         .throttleLast(800L, TimeUnit.MILLISECONDS)
  54.         .timestamp()
  55.         .distinctUntilChanged { t1, t2 ->
  56.             val sameValue = t1.value() == t2.value()
  57.             val dropSameValue = t2.time() - t1.time() < 2000L
  58.  
  59.             Timber.d("sameValue=$sameValue, dropSameValue=$dropSameValue")
  60.  
  61.             sameValue && dropSameValue
  62.         }
  63.         .doOnNext { Timber.d("Barcode: $it") }
  64.         .map { verifyBarcode(it.value()) }
  65.         .observeOn(mainThread())
  66.         .subscribeBy { result ->
  67.             verificationResultEvents.value = result
  68.             viewState.mutateValue { state ->
  69.                 updateViewState(state, result)
  70.             }
  71.         }
  72.  
  73.     private fun verifyBarcode(barcode: String): BarcodeVerificationResult {
  74.         val product = session.findProductByBarcode(barcode)
  75.             ?: return BarcodeVerificationResult.UnknownBarcode(barcode)
  76.  
  77.         return if (viewState.requireValue().mode == ADD_MODE) {
  78.             mapToVerificationResult(session.addProduct(product.id), product)
  79.         } else {
  80.             mapToVerificationResult(session.removeProduct(product.id), product)
  81.         }
  82.     }
  83.  
  84.     private fun mapToVerificationResult(
  85.         changeResult: ChangeResult,
  86.         product: Product
  87.     ): BarcodeVerificationResult =
  88.         when (changeResult) {
  89.             is ChangeResult.Added -> {
  90.                 BarcodeVerificationResult.PositionAdded(
  91.                     productId = product.id,
  92.                     productName = product.name,
  93.                     scannedQty = changeResult.newQty
  94.                 )
  95.             }
  96.             is ChangeResult.Removed -> {
  97.                 BarcodeVerificationResult.PositionRemoved(
  98.                     productId = product.id,
  99.                     productName = product.name,
  100.                     scannedQty = changeResult.newQty
  101.                 )
  102.             }
  103.             is ChangeResult.LimitExceeded -> {
  104.                 BarcodeVerificationResult.CanNotAddMore(productName = product.name)
  105.             }
  106.             is ChangeResult.NoProduct -> {
  107.                 BarcodeVerificationResult.CanNotRemove(productName = product.name)
  108.             }
  109.         }
  110.  
  111.     private fun updateViewState(viewState: ViewState, result: BarcodeVerificationResult) {
  112.         when (result) {
  113.             is BarcodeVerificationResult.PositionAdded -> {
  114.                 viewState.updatePositionQty(result.productId, result.scannedQty)
  115.             }
  116.             is BarcodeVerificationResult.PositionRemoved -> {
  117.                 viewState.updatePositionQty(result.productId, result.scannedQty)
  118.             }
  119.         }
  120.     }
  121.  
  122.     fun switchToRemoveScanMode() {
  123.         viewState.mutateValue {
  124.             it.mode = REMOVE_MODE
  125.         }
  126.     }
  127.  
  128.     fun switchToAddScanMode() {
  129.         viewState.mutateValue {
  130.             it.mode = ADD_MODE
  131.         }
  132.     }
  133.  
  134.     fun addPosition(barcode: String) {
  135.         val result = session.findProductByBarcode(barcode)?.let {
  136.             mapToVerificationResult(session.addProduct(it.id), it)
  137.         } ?: BarcodeVerificationResult.UnknownBarcode(barcode)
  138.  
  139.         verificationResultEvents.value = result
  140.  
  141.         viewState.mutateValue { state ->
  142.             updateViewState(state, result)
  143.         }
  144.     }
  145.  
  146.     fun removePosition(barcode: String) {
  147.         val result = session.findProductByBarcode(barcode)?.let {
  148.             mapToVerificationResult(session.removeProduct(it.id), it)
  149.         } ?: BarcodeVerificationResult.UnknownBarcode(barcode)
  150.  
  151.         verificationResultEvents.value = result
  152.  
  153.         viewState.mutateValue { state ->
  154.             updateViewState(state, result)
  155.         }
  156.     }
  157.  
  158.     fun applyBarcode(barcode: String) {
  159.         barcodeSubject.onNext(barcode)
  160.     }
  161.  
  162.     fun pauseBarcodeVerification() {
  163.         skipBarcodes = true
  164.     }
  165.  
  166.     fun resumeBarcodeVerification() {
  167.         skipBarcodes = false
  168.     }
  169.  
  170.     fun getViewState(): LiveData<ViewState> = viewState
  171.  
  172.     fun getVerificationEvents(): SingleLiveEvent<BarcodeVerificationResult> =
  173.         verificationResultEvents
  174.  
  175.     fun goBack() {
  176.         router.exit()
  177.     }
  178.  
  179.     override fun onCleared() {
  180.         barcodesDisposable.dispose()
  181.         coroutineScope.cancel()
  182.         super.onCleared()
  183.     }
  184.  
  185.     data class ViewState(
  186.         @ScanMode var mode: Int,
  187.         val totalGoodsQty: Int,
  188.         val positions: List<PositionState> = mutableListOf()
  189.     ) {
  190.  
  191.         var scannedGoodsQty: Int = 0
  192.             private set
  193.  
  194.         fun updatePositionQty(productId: String, qty: Int) {
  195.             positions.find { it.id == productId }?.scannedQty = qty
  196.             scannedGoodsQty = positions.sumBy { it.scannedQty }
  197.         }
  198.  
  199.         @IntDef(value = [ADD_MODE, REMOVE_MODE])
  200.         annotation class ScanMode
  201.     }
  202.  
  203.     sealed class BarcodeVerificationResult {
  204.  
  205.         class PositionAdded(
  206.             val productId: String,
  207.             val productName: String,
  208.             val scannedQty: Int
  209.         ) : BarcodeVerificationResult()
  210.  
  211.         class PositionRemoved(
  212.             val productId: String,
  213.             val productName: String,
  214.             val scannedQty: Int
  215.         ) : BarcodeVerificationResult()
  216.  
  217.         class CanNotAddMore(
  218.             val productName: String
  219.         ) : BarcodeVerificationResult()
  220.  
  221.         class CanNotRemove(
  222.             val productName: String
  223.         ) : BarcodeVerificationResult()
  224.  
  225.         class UnknownBarcode(
  226.             val barcode: String
  227.         ) : BarcodeVerificationResult()
  228.     }
  229.  
  230.     @AssistedInject.Factory
  231.     interface Factory {
  232.  
  233.         fun create(orderId: String): GoodsScannerViewModel
  234.     }
  235.  
  236.     companion object {
  237.         const val ADD_MODE = 0
  238.         const val REMOVE_MODE = 1
  239.     }
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement