From ec1d6e5e61029a18c85d4a87041c807c34cb324f Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 9 Jan 2023 12:59:34 +0400 Subject: [PATCH 1/7] Add cart module and requests queue helper --- cart-utils/.gitignore | 1 + cart-utils/build.gradle | 22 +++++++++++ cart-utils/src/main/AndroidManifest.xml | 1 + .../cart_utils/requests_qeue/RequestsQueue.kt | 39 +++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 cart-utils/.gitignore create mode 100644 cart-utils/build.gradle create mode 100644 cart-utils/src/main/AndroidManifest.xml create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/requests_qeue/RequestsQueue.kt diff --git a/cart-utils/.gitignore b/cart-utils/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/cart-utils/.gitignore @@ -0,0 +1 @@ +/build diff --git a/cart-utils/build.gradle b/cart-utils/build.gradle new file mode 100644 index 0000000..ff9abdc --- /dev/null +++ b/cart-utils/build.gradle @@ -0,0 +1,22 @@ +apply from: "../android-configs/lib-config.gradle" + +dependencies { + def coroutinesVersion = '1.6.4' + def junitVersion = '4.13.2' + + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") + testImplementation("junit:junit") + + constraints { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") { + version { + require(coroutinesVersion) + } + } + testImplementation("junit:junit") { + version { + require(junitVersion) + } + } + } +} diff --git a/cart-utils/src/main/AndroidManifest.xml b/cart-utils/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8a05ba2 --- /dev/null +++ b/cart-utils/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/requests_qeue/RequestsQueue.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/requests_qeue/RequestsQueue.kt new file mode 100644 index 0000000..d84a95d --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/requests_qeue/RequestsQueue.kt @@ -0,0 +1,39 @@ +package ru.touchin.roboswag.cart_utils.requests_qeue + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.consumeAsFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +/** + * Queue for abstract requests which will be executed one after another + */ +typealias Request = suspend () -> TResponse + +class RequestsQueue> { + + private val requestChannel = Channel(capacity = Channel.BUFFERED) + + fun initRequestsExecution( + coroutineScope: CoroutineScope, + executeRequestAction: suspend (TRequest) -> Unit, + ) { + requestChannel + .consumeAsFlow() + .onEach { executeRequestAction.invoke(it) } + .launchIn(coroutineScope) + } + + fun addToQueue(request: TRequest) { + requestChannel.trySend(request) + } + + fun clearQueue() { + while (hasPendingRequests()) requestChannel.tryReceive() + } + + @OptIn(ExperimentalCoroutinesApi::class) + fun hasPendingRequests() = !requestChannel.isEmpty +} From 28b362ce002ef2d0e902037b0a72ace4f4ba123c Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 9 Jan 2023 13:00:37 +0400 Subject: [PATCH 2/7] Add generic cart models and CartUpdateManager --- .../roboswag/cart_utils/models/CartModel.kt | 19 +++ .../cart_utils/models/ProductModel.kt | 19 +++ .../repositories/IRemoteCartRepository.kt | 19 +++ .../repositories/LocalCartRepository.kt | 64 ++++++++++ .../update_manager/CartUpdateManager.kt | 113 ++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/IRemoteCartRepository.kt create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt new file mode 100644 index 0000000..e95b549 --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt @@ -0,0 +1,19 @@ +package ru.touchin.roboswag.cart_utils.models + +abstract class CartModel { + + abstract val products: List + + val availableProducts: List + get() = products.filter { it.isAvailable && !it.isDeleted } + + val totalPrice: Int + get() = availableProducts.sumOf { it.price } + + abstract fun copyWith( + products: List = this.products, + ): TCart + + @Suppress("UNCHECKED_CAST") + fun asCart() = this as TCart +} diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt new file mode 100644 index 0000000..56e192b --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt @@ -0,0 +1,19 @@ +package ru.touchin.roboswag.cart_utils.models + +abstract class ProductModel { + abstract val id: Int + abstract val countInCart: Int + abstract val price: Int + abstract val isAvailable: Boolean + abstract val isDeleted: Boolean + + open val variants: List = emptyList() + + abstract fun copyWith( + countInCart: Int = this.countInCart, + isDeleted: Boolean = this.isDeleted, + ): TProduct + + @Suppress("UNCHECKED_CAST") + fun asProduct(): TProduct = this as TProduct +} diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/IRemoteCartRepository.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/IRemoteCartRepository.kt new file mode 100644 index 0000000..149a960 --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/IRemoteCartRepository.kt @@ -0,0 +1,19 @@ +package ru.touchin.roboswag.cart_utils.repositories + +import ru.touchin.roboswag.cart_utils.models.CartModel +import ru.touchin.roboswag.cart_utils.models.ProductModel + +/** + * Interface for server-side cart repository where each request should return updated [CartModel] + */ +interface IRemoteCartRepository, TProduct : ProductModel> { + + suspend fun getCart(): TCart + + suspend fun addProduct(product: TProduct): TCart + + suspend fun removeProduct(id: Int): TCart + + suspend fun editProductCount(id: Int, count: Int): TCart + +} diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt new file mode 100644 index 0000000..fb7b2ba --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt @@ -0,0 +1,64 @@ +package ru.touchin.roboswag.cart_utils.repositories + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import ru.touchin.roboswag.cart_utils.models.CartModel +import ru.touchin.roboswag.cart_utils.models.ProductModel + +/** + * Class that contains StateFlow of current [CartModel] which can be subscribed in ViewModels + */ +class LocalCartRepository, TProduct : ProductModel>( + initialCart: TCart +) { + + private val _currentCart = MutableStateFlow(initialCart) + val currentCart = _currentCart.asStateFlow() + + fun updateCart(cart: TCart) { + _currentCart.value = cart + } + + fun addProduct(product: TProduct) { + updateCartProducts { + add(product) + } + } + + fun removeProduct(id: Int) { + updateCartProducts { + val product = find { it.id == id } + remove(product) + } + } + + fun editProductCount(id: Int, count: Int) { + updateCartProducts { + updateProduct(id) { copyWith(countInCart = count) } + } + } + + fun markProductDeleted(id: Int) { + updateCartProducts { + updateProduct(id) { copyWith(isDeleted = true) } + } + } + + fun restoreDeletedProduct(id: Int) { + updateCartProducts { + updateProduct(id) { copyWith(isDeleted = false) } + } + } + + private fun updateCartProducts(updateAction: MutableList.() -> Unit) { + _currentCart.update { cart -> + cart.copyWith(products = cart.products.toMutableList().apply(updateAction)) + } + } + + private fun MutableList.updateProduct(id: Int, updateAction: TProduct.() -> TProduct) { + val index = indexOfFirst { it.id == id } + if (index >= 0) this[index] = updateAction.invoke(this[index]) + } +} diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt new file mode 100644 index 0000000..5c2a143 --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt @@ -0,0 +1,113 @@ +package ru.touchin.roboswag.cart_utils.update_manager + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import ru.touchin.roboswag.cart_utils.models.CartModel +import ru.touchin.roboswag.cart_utils.models.ProductModel +import ru.touchin.roboswag.cart_utils.repositories.IRemoteCartRepository +import ru.touchin.roboswag.cart_utils.repositories.LocalCartRepository +import ru.touchin.roboswag.cart_utils.requests_qeue.Request +import ru.touchin.roboswag.cart_utils.requests_qeue.RequestsQueue + +/** + * Combines local and remote cart update actions + */ +open class CartUpdateManager, TProduct : ProductModel>( + private val localCartRepository: LocalCartRepository, + private val remoteCartRepository: IRemoteCartRepository, + private val maxRequestAttemptsCount: Int = MAX_REQUEST_CART_ATTEMPTS_COUNT, + private val errorHandler: (Throwable) -> Unit = {}, +) { + + companion object { + private const val MAX_REQUEST_CART_ATTEMPTS_COUNT = 3 + } + + private val requestsQueue = RequestsQueue>() + + @Volatile + var lastRemoteCart: TCart? = null + private set + + fun initCartRequestsQueue( + coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO), + ) { + requestsQueue.initRequestsExecution(coroutineScope) { request -> + runCatching { + lastRemoteCart = request.invoke() + if (!requestsQueue.hasPendingRequests()) updateLocalCartWithRemote() + }.onFailure { error -> + errorHandler.invoke(error) + requestsQueue.clearQueue() + tryToGetRemoteCartAgain() + } + } + } + + open fun addProduct(product: TProduct, restoreDeleted: Boolean = false) { + with(localCartRepository) { + if (restoreDeleted) restoreDeletedProduct(product.id) else addProduct(product) + } + + requestsQueue.addToQueue { + remoteCartRepository.addProduct(product) + } + } + + open fun removeProduct(id: Int, markDeleted: Boolean = false) { + with(localCartRepository) { + if (markDeleted) markProductDeleted(id) else removeProduct(id) + } + + requestsQueue.addToQueue { + remoteCartRepository.removeProduct(id) + } + } + + open fun editProductCount(id: Int, count: Int) { + localCartRepository.editProductCount(id, count) + + requestsQueue.addToQueue { + remoteCartRepository.editProductCount(id, count) + } + } + + open fun completelyDeleteProduct(id: Int) { + localCartRepository.removeProduct(id) + } + + private suspend fun tryToGetRemoteCartAgain() { + repeat(maxRequestAttemptsCount) { + runCatching { + lastRemoteCart = remoteCartRepository.getCart() + updateLocalCartWithRemote() + return + } + } + } + + private fun updateLocalCartWithRemote() { + val remoteCart = lastRemoteCart ?: return + val remoteProducts = remoteCart.products + val localProducts = localCartRepository.currentCart.value.products + + val newProductsFromRemoteCart = remoteProducts.filter { remoteProduct -> + localProducts.none { it.id == remoteProduct.id } + } + + val mergedProducts = localProducts.mapNotNull { localProduct -> + val sameRemoteProduct = remoteProducts.find { it.id == localProduct.id } + + when { + sameRemoteProduct != null -> sameRemoteProduct + localProduct.isDeleted -> localProduct + else -> null + } + } + + val mergedCart = remoteCart.copyWith(products = mergedProducts + newProductsFromRemoteCart) + localCartRepository.updateCart(mergedCart) + } + +} From 8a0ed4ca064a1d1012017e28eb620ed099f11316 Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 9 Jan 2023 14:18:14 +0400 Subject: [PATCH 3/7] Add promocode list and calculate discount --- .../roboswag/cart_utils/models/CartModel.kt | 10 +++++++++- .../cart_utils/models/PromocodeModel.kt | 19 +++++++++++++++++++ .../repositories/LocalCartRepository.kt | 18 ++++++++++++++++-- .../update_manager/CartUpdateManager.kt | 9 +++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt index e95b549..c6c84ff 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt @@ -4,14 +4,22 @@ abstract class CartModel { abstract val products: List + open val promocodeList: List = emptyList() + val availableProducts: List get() = products.filter { it.isAvailable && !it.isDeleted } val totalPrice: Int - get() = availableProducts.sumOf { it.price } + get() = availableProducts.sumOf { it.countInCart * it.price } + + val priceWithPromocode: Int + get() = promocodeList + .sortedByDescending { it.discount is PromocodeDiscount.ByPercent } + .fold(initial = totalPrice) { price, promo -> promo.discount.applyTo(price) } abstract fun copyWith( products: List = this.products, + promocodeList: List = this.promocodeList ): TCart @Suppress("UNCHECKED_CAST") diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt new file mode 100644 index 0000000..261c9b2 --- /dev/null +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt @@ -0,0 +1,19 @@ +package ru.touchin.roboswag.cart_utils.models + +open class PromocodeModel( + val code: String, + val discount: PromocodeDiscount, +) + +abstract class PromocodeDiscount { + + abstract fun applyTo(totalPrice: Int): Int + + class ByValue(private val value: Int) : PromocodeDiscount() { + override fun applyTo(totalPrice: Int): Int = totalPrice - value + } + + class ByPercent(private val percent: Int) : PromocodeDiscount() { + override fun applyTo(totalPrice: Int): Int = totalPrice - (totalPrice * percent / 100) + } +} diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt index fb7b2ba..8e861b5 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import ru.touchin.roboswag.cart_utils.models.CartModel import ru.touchin.roboswag.cart_utils.models.ProductModel +import ru.touchin.roboswag.cart_utils.models.PromocodeModel /** * Class that contains StateFlow of current [CartModel] which can be subscribed in ViewModels @@ -28,8 +29,7 @@ class LocalCartRepository, TProduct : ProductModel>( fun removeProduct(id: Int) { updateCartProducts { - val product = find { it.id == id } - remove(product) + remove(find { it.id == id }) } } @@ -51,12 +51,26 @@ class LocalCartRepository, TProduct : ProductModel>( } } + fun applyPromocode(promocode: PromocodeModel) { + updatePromocodeList { add(promocode) } + } + + fun removePromocode(code: String) { + updatePromocodeList { removeAt(indexOfFirst { it.code == code }) } + } + private fun updateCartProducts(updateAction: MutableList.() -> Unit) { _currentCart.update { cart -> cart.copyWith(products = cart.products.toMutableList().apply(updateAction)) } } + private fun updatePromocodeList(updateAction: MutableList.() -> Unit) { + _currentCart.update { cart -> + cart.copyWith(promocodeList = cart.promocodeList.toMutableList().apply(updateAction)) + } + } + private fun MutableList.updateProduct(id: Int, updateAction: TProduct.() -> TProduct) { val index = indexOfFirst { it.id == id } if (index >= 0) this[index] = updateAction.invoke(this[index]) diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt index 5c2a143..57b7e6c 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import ru.touchin.roboswag.cart_utils.models.CartModel import ru.touchin.roboswag.cart_utils.models.ProductModel +import ru.touchin.roboswag.cart_utils.models.PromocodeModel import ru.touchin.roboswag.cart_utils.repositories.IRemoteCartRepository import ru.touchin.roboswag.cart_utils.repositories.LocalCartRepository import ru.touchin.roboswag.cart_utils.requests_qeue.Request @@ -77,6 +78,14 @@ open class CartUpdateManager, TProduct : ProductMode localCartRepository.removeProduct(id) } + open fun applyPromocode(promocode: PromocodeModel) { + localCartRepository.applyPromocode(promocode) + } + + open fun removePromocode(code: String) { + localCartRepository.removePromocode(code) + } + private suspend fun tryToGetRemoteCartAgain() { repeat(maxRequestAttemptsCount) { runCatching { From 33a745e5e0395e2b6e05e9d4c90da53114cf981b Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 9 Jan 2023 15:02:00 +0400 Subject: [PATCH 4/7] Add bonuses field to cart and products --- .../roboswag/cart_utils/models/CartModel.kt | 16 +++++++++++----- .../roboswag/cart_utils/models/ProductModel.kt | 1 + .../repositories/LocalCartRepository.kt | 5 +++++ .../update_manager/CartUpdateManager.kt | 13 ------------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt index c6c84ff..5f44d83 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt @@ -6,20 +6,26 @@ abstract class CartModel { open val promocodeList: List = emptyList() + open val availableBonuses: Int = 0 + open val usedBonuses: Int = 0 + val availableProducts: List get() = products.filter { it.isAvailable && !it.isDeleted } val totalPrice: Int get() = availableProducts.sumOf { it.countInCart * it.price } - val priceWithPromocode: Int - get() = promocodeList - .sortedByDescending { it.discount is PromocodeDiscount.ByPercent } - .fold(initial = totalPrice) { price, promo -> promo.discount.applyTo(price) } + val totalBonuses: Int + get() = availableProducts.sumOf { it.countInCart * (it.bonuses ?: 0) } + + fun getPriceWithPromocode(): Int = promocodeList + .sortedByDescending { it.discount is PromocodeDiscount.ByPercent } + .fold(initial = totalPrice) { price, promo -> promo.discount.applyTo(price) } abstract fun copyWith( products: List = this.products, - promocodeList: List = this.promocodeList + promocodeList: List = this.promocodeList, + usedBonuses: Int = this.usedBonuses ): TCart @Suppress("UNCHECKED_CAST") diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt index 56e192b..d825a80 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt @@ -7,6 +7,7 @@ abstract class ProductModel { abstract val isAvailable: Boolean abstract val isDeleted: Boolean + open val bonuses: Int? = null open val variants: List = emptyList() abstract fun copyWith( diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt index 8e861b5..7183514 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt @@ -59,6 +59,11 @@ class LocalCartRepository, TProduct : ProductModel>( updatePromocodeList { removeAt(indexOfFirst { it.code == code }) } } + fun useBonuses(bonuses: Int) { + require(currentCart.value.availableBonuses >= bonuses) { "Can't use bonuses more than available" } + _currentCart.update { it.copyWith(usedBonuses = bonuses) } + } + private fun updateCartProducts(updateAction: MutableList.() -> Unit) { _currentCart.update { cart -> cart.copyWith(products = cart.products.toMutableList().apply(updateAction)) diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt index 57b7e6c..8a68bac 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt @@ -5,7 +5,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import ru.touchin.roboswag.cart_utils.models.CartModel import ru.touchin.roboswag.cart_utils.models.ProductModel -import ru.touchin.roboswag.cart_utils.models.PromocodeModel import ru.touchin.roboswag.cart_utils.repositories.IRemoteCartRepository import ru.touchin.roboswag.cart_utils.repositories.LocalCartRepository import ru.touchin.roboswag.cart_utils.requests_qeue.Request @@ -74,18 +73,6 @@ open class CartUpdateManager, TProduct : ProductMode } } - open fun completelyDeleteProduct(id: Int) { - localCartRepository.removeProduct(id) - } - - open fun applyPromocode(promocode: PromocodeModel) { - localCartRepository.applyPromocode(promocode) - } - - open fun removePromocode(code: String) { - localCartRepository.removePromocode(code) - } - private suspend fun tryToGetRemoteCartAgain() { repeat(maxRequestAttemptsCount) { runCatching { From 724c2ca3b83fbb53431a9aa5ecc988986cfea379 Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 9 Jan 2023 16:34:06 +0400 Subject: [PATCH 5/7] Add variants selecting --- .../touchin/roboswag/cart_utils/models/CartModel.kt | 4 +++- .../roboswag/cart_utils/models/ProductModel.kt | 5 +++++ .../cart_utils/repositories/LocalCartRepository.kt | 13 +++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt index 5f44d83..baa8ed5 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/CartModel.kt @@ -20,7 +20,9 @@ abstract class CartModel { fun getPriceWithPromocode(): Int = promocodeList .sortedByDescending { it.discount is PromocodeDiscount.ByPercent } - .fold(initial = totalPrice) { price, promo -> promo.discount.applyTo(price) } + .fold(initial = totalPrice) { price, promo -> + promo.discount.applyTo(price) + } abstract fun copyWith( products: List = this.products, diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt index d825a80..56c2758 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/ProductModel.kt @@ -8,11 +8,16 @@ abstract class ProductModel { abstract val isDeleted: Boolean open val bonuses: Int? = null + open val variants: List = emptyList() + open val selectedVariantId: Int? = null + + val selectedVariant get() = variants.find { it.id == selectedVariantId } abstract fun copyWith( countInCart: Int = this.countInCart, isDeleted: Boolean = this.isDeleted, + selectedVariantId: Int? = this.selectedVariantId ): TProduct @Suppress("UNCHECKED_CAST") diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt index 7183514..9746e47 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/repositories/LocalCartRepository.kt @@ -64,6 +64,19 @@ class LocalCartRepository, TProduct : ProductModel>( _currentCart.update { it.copyWith(usedBonuses = bonuses) } } + fun chooseVariant(productId: Int, variantId: Int?) { + updateCartProducts { + updateProduct(productId) { + if (variantId != null) { + check(variants.any { it.id == variantId }) { + "Product with id=$productId doesn't have variant with id=$variantId" + } + } + copyWith(selectedVariantId = variantId) + } + } + } + private fun updateCartProducts(updateAction: MutableList.() -> Unit) { _currentCart.update { cart -> cart.copyWith(products = cart.products.toMutableList().apply(updateAction)) From 4dc9e7e478eb5b0c9c5262e01c7b752a7ec58bc1 Mon Sep 17 00:00:00 2001 From: Grigorii Date: Mon, 9 Jan 2023 16:45:35 +0400 Subject: [PATCH 6/7] Fix detekt --- .../ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt index 261c9b2..aab308d 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/models/PromocodeModel.kt @@ -14,6 +14,6 @@ abstract class PromocodeDiscount { } class ByPercent(private val percent: Int) : PromocodeDiscount() { - override fun applyTo(totalPrice: Int): Int = totalPrice - (totalPrice * percent / 100) + override fun applyTo(totalPrice: Int): Int = totalPrice - totalPrice * percent / 100 } } From c30dc55e0803abea2bab83f380ac702093c872e3 Mon Sep 17 00:00:00 2001 From: Grigorii Date: Thu, 23 Mar 2023 18:56:46 +0400 Subject: [PATCH 7/7] add new line --- .../roboswag/cart_utils/update_manager/CartUpdateManager.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt index 8a68bac..41b5a88 100644 --- a/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt +++ b/cart-utils/src/main/java/ru/touchin/roboswag/cart_utils/update_manager/CartUpdateManager.kt @@ -78,6 +78,7 @@ open class CartUpdateManager, TProduct : ProductMode runCatching { lastRemoteCart = remoteCartRepository.getCart() updateLocalCartWithRemote() + return } }