diff --git a/domain/card/build.gradle.kts b/domain/card/build.gradle.kts index 0da92b17b4..213bd024b6 100644 --- a/domain/card/build.gradle.kts +++ b/domain/card/build.gradle.kts @@ -1,6 +1,5 @@ plugins { alias(deps.plugins.kotlin.jvm) - alias(deps.plugins.kotlin.kapt) id("configuration") } @@ -10,9 +9,4 @@ dependencies { implementation(project(":domain:models")) implementation(deps.tangem.card.core) - - implementation(deps.hilt.core) - kapt(deps.hilt.kapt) - - implementation(deps.moshi.kotlin) } \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardException.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardException.kt index b1000aa283..b9d3e287ac 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardException.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardException.kt @@ -1,14 +1,14 @@ package com.tangem.domain.card -import com.tangem.common.core.TangemSdkError - // TODO: May be add new error types sealed class ScanCardException : Exception() { object WrongCardId : ScanCardException() object UserCancelled : ScanCardException() + object WrongAccessCode : ScanCardException() + open class ChainException : ScanCardException() - class SdkException(override val cause: TangemSdkError) : ScanCardException() + class UnknownException(override val cause: Exception) : ScanCardException() } \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt index 88de647d8d..0365ac58ae 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt @@ -1,16 +1,15 @@ package com.tangem.domain.card +import arrow.core.Either import arrow.core.EitherNel import arrow.core.flatMap -import arrow.core.toEitherNel import com.tangem.TangemSdk import com.tangem.common.core.CardIdDisplayFormat -import com.tangem.domain.card.model.ScanCardParams import com.tangem.domain.card.repository.ScanCardRepository +import com.tangem.domain.core.chain.Chain import com.tangem.domain.core.chain.ChainProcessor import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse -import javax.inject.Inject /** * Use case responsible for scanning a card and returning a [ScanResponse] object. @@ -18,7 +17,7 @@ import javax.inject.Inject * @property tangemSdk An instance of [TangemSdk] to configure the display format of the card ID. * @constructor Create a new instance of [ScanCardUseCase] with the given dependencies. */ -class ScanCardUseCase @Inject internal constructor( +class ScanCardUseCase( private val scanCardRepository: ScanCardRepository, private val tangemSdk: TangemSdk, ) { @@ -32,23 +31,31 @@ class ScanCardUseCase @Inject internal constructor( /** * Scan a card and return a [ScanResponse] object. - * @param params An instance of [ScanCardParams] to configure the scan process. + * @param cardId an optional card ID to scan. If null, can scan any card present. + * Defaults to null. + * @param allowRequestAccessCodeFromStorage whether to prompt the user for an access code if needed. + * Defaults to false. + * @param afterScanChains An array of chains that should be executed after a successful card scan operation. + * Defaults to an empty array. * @return A [EitherNel] object with either a non-empty list of [ScanCardException] or a [ScanResponse]. */ - suspend operator fun invoke(params: ScanCardParams = ScanCardParams()): EitherNel { + suspend operator fun invoke( + cardId: String? = null, + allowRequestAccessCodeFromStorage: Boolean = false, + afterScanChains: Array> = emptyArray(), + ): Either { resetCardIdDisplayFormat() - scanChainProcessor.addChains(*params.afterScanChains) + scanChainProcessor.addChains(afterScanChains) return scanCardRepository.scanCard( - cardId = params.cardId, - allowRequestAccessCodeFromRepository = params.allowRequestAccessCodeFromRepository, + cardId = cardId, + allowRequestAccessCodeFromStorage = allowRequestAccessCodeFromStorage, ) .onRight { scanResponse -> updateCardIdDisplayFormat(scanResponse.productType) } - .toEitherNel() - .flatMap { scanResponse -> - scanChainProcessor.launchChains(initial = scanResponse) + .flatMap { response -> + scanChainProcessor.launchChains(initial = response) } } diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/di/CardDomainModule.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/di/CardDomainModule.kt deleted file mode 100644 index 592df6a876..0000000000 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/di/CardDomainModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tangem.domain.card.di - -import com.tangem.TangemSdk -import com.tangem.domain.card.ScanCardUseCase -import com.tangem.domain.card.repository.ScanCardRepository -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -class CardDomainModule { - - @Provides - fun provideScanCardUseCase(scanCardRepository: ScanCardRepository, tangemSdk: TangemSdk) = - ScanCardUseCase(scanCardRepository, tangemSdk) -} \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/model/ScanCardParams.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/model/ScanCardParams.kt deleted file mode 100644 index 2fa7fd798d..0000000000 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/model/ScanCardParams.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.domain.card.model - -import com.tangem.domain.card.ScanCardException -import com.tangem.domain.core.chain.Chain -import com.tangem.domain.models.scan.ScanResponse - -/** - * Represents the parameters to be used during a card scanning operation. - * - * @property cardId an optional card ID to scan. If null, can scan any card present. - * Defaults to null. - * @property allowRequestAccessCodeFromRepository whether to prompt the user for an access code if needed. - * Defaults to false. - * @property afterScanChains An array of chains that should be executed after a successful card scan operation. - * Defaults to an empty array. - */ -class ScanCardParams( - val cardId: String? = null, - val allowRequestAccessCodeFromRepository: Boolean = false, - val afterScanChains: Array> = emptyArray(), -) \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt index 0fce5103c1..2de00090cf 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt @@ -10,15 +10,15 @@ import com.tangem.domain.models.scan.ScanResponse interface ScanCardRepository { /** - * Scans the card with the given [cardId] and returns a [ScanResponse]. If [allowRequestAccessCodeFromRepository] - * is true, the repository may prompt the user for an access code. + * Scans the card with the given [cardId] and returns a [ScanResponse] * * @param cardId an optional card ID to scan. If null, the repository should scan any card present. - * @param allowRequestAccessCodeFromRepository whether to prompt the user for an access code if needed. + * @param allowRequestAccessCodeFromStorage whether the access code can be requested from + * internal storage during the scan process * @return an [Either] that contains a [ScanCardException] in case of an error or a [ScanResponse]. */ suspend fun scanCard( cardId: String?, - allowRequestAccessCodeFromRepository: Boolean, + allowRequestAccessCodeFromStorage: Boolean, ): Either } \ No newline at end of file diff --git a/domain/core/src/main/kotlin/com/tangem/domain/core/chain/Chain.kt b/domain/core/src/main/kotlin/com/tangem/domain/core/chain/Chain.kt index 57ec9f59b2..a7e0d5bc38 100644 --- a/domain/core/src/main/kotlin/com/tangem/domain/core/chain/Chain.kt +++ b/domain/core/src/main/kotlin/com/tangem/domain/core/chain/Chain.kt @@ -1,7 +1,6 @@ package com.tangem.domain.core.chain import arrow.core.Either -import arrow.core.EitherNel /** * A chain in the [ChainProcessor] class for processing a chain of operations with the ability to handle errors. @@ -12,8 +11,8 @@ interface Chain { /** * Invokes the chain with the previous chain result as input and returns an [Either] result. - * @param previousChainResult the previous chain result as an [EitherNel] + * @param previousChainResult the previous chain result as an [R] * @return the result of the chain processing as an [Either] */ - suspend operator fun invoke(previousChainResult: EitherNel): Either + suspend operator fun invoke(previousChainResult: R): Either } \ No newline at end of file diff --git a/domain/core/src/main/kotlin/com/tangem/domain/core/chain/ChainProcessor.kt b/domain/core/src/main/kotlin/com/tangem/domain/core/chain/ChainProcessor.kt index 334af39b0e..13101be7fd 100644 --- a/domain/core/src/main/kotlin/com/tangem/domain/core/chain/ChainProcessor.kt +++ b/domain/core/src/main/kotlin/com/tangem/domain/core/chain/ChainProcessor.kt @@ -1,12 +1,10 @@ package com.tangem.domain.core.chain import arrow.core.Either -import arrow.core.EitherNel -import arrow.core.left -import arrow.core.nel -import arrow.core.right -import arrow.core.toEitherNel +import arrow.core.raise.either +// TODO: Create Ior implementation +// TODO: Create accumulate implementation /** * A class for processing a chain of operations with the ability to handle errors. * @param E the type of error @@ -23,41 +21,15 @@ class ChainProcessor { * Adds chains to the existing list of chains to be executed. * @param chains the chains to be added to the list */ - fun addChains(vararg chains: Chain) { + fun addChains(chains: Array>) { this.chains.addAll(chains) } - /** - * Launches the chains with the given initial value as input. - * @param initial the initial value to start the chain processing. - * @param accumulateExceptions determines whether to accumulate exceptions or break on first exception. - * Defaults to true. - * @return the result of the chain processing as an EitherNel, which is a disjunction that may contain multiple errors. - */ - private suspend fun launchChains(initial: Either, accumulateExceptions: Boolean = true): EitherNel { - return chains.fold(initial.toEitherNel()) { previousChainResult, chain -> - chain.invoke(previousChainResult) - .mapLeft { e -> - previousChainResult.leftOrNull()?.plus(e) - ?: e.nel() - } - .onLeft { e -> - if (!accumulateExceptions) { - return e.left() - } - } + suspend fun launchChains(initial: R): Either { + return either { + chains.fold(initial) { prevChainResult, chain -> + chain.invoke(prevChainResult).bind() + } } } - - /** - * Launches the chains with the given initial value as input. - * This function is a convenience function that assumes the initial value does not contain any errors. - * @param initial the initial value to start the chain processing. - * @param accumulateExceptions determines whether to accumulate exceptions or break on first exception. - * Defaults to true. - * @return the result of the chain processing as an EitherNel, which is a disjunction that may contain multiple errors. - */ - suspend fun launchChains(initial: R, accumulateExceptions: Boolean = true): EitherNel { - return launchChains(initial.right(), accumulateExceptions) - } } \ No newline at end of file