diff --git a/app/build.gradle b/app/build.gradle index 6cc910a506..78402e567b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -69,8 +69,8 @@ repositories { dependencies { implementation fileTree(include: ['*.aar'], dir: 'libs') implementation implementation(project(path: ':domain')) - // TODO: refactoring: only for backwards compatibility with non-relocated services to the network module implementation implementation(project(path: ':network')) + implementation implementation(project(path: ':common')) implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' diff --git a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt index d498d577f8..5031d9d835 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt @@ -20,7 +20,7 @@ import com.tangem.domain.DomainDialog import com.tangem.domain.redux.domainStore import com.tangem.domain.redux.global.DomainGlobalAction import com.tangem.domain.redux.global.DomainGlobalState -import com.tangem.tap.features.tokens.addCustomToken.DomainErrorConverter +import com.tangem.tap.common.moduleMessage.ModuleMessageConverter import com.tangem.tap.features.tokens.addCustomToken.compose.SelectTokenNetworkDialog import com.tangem.wallet.R import org.rekotlin.StoreSubscriber @@ -55,13 +55,13 @@ private fun ShowTheDialog(dialogState: MutableState) { if (dialogState.value == null) return val context = LocalContext.current - val errorConverter = remember { DomainErrorConverter(context) } + val errorConverter = remember { ModuleMessageConverter(context) } val onDismissRequest = { domainStore.dispatch(DomainGlobalAction.ShowDialog(null)) } when (val dialog = dialogState.value) { is DomainDialog.DialogError -> ErrorDialog( title = stringResource(id = R.string.common_error), - body = errorConverter.convertError(dialog.error), + body = errorConverter.convert(dialog.error), onDismissRequest ) is DomainDialog.SelectTokenDialog -> SelectTokenNetworkDialog(dialog, onDismissRequest) diff --git a/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt b/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt index 0d7d4f44e9..3081ef0b45 100644 --- a/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt +++ b/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt @@ -15,16 +15,17 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.tangem.domain.DomainError -import com.tangem.domain.ErrorConverter +import com.tangem.common.module.ModuleError import com.tangem.domain.common.form.Field import com.tangem.tap.common.compose.extensions.stringResourceDefault +import com.tangem.tap.common.moduleMessage.ModuleMessageConverter /** [REDACTED_AUTHOR] @@ -41,8 +42,8 @@ fun OutlinedTextFieldWidget( isEnabled: Boolean = true, isVisible: Boolean = true, isLoading: Boolean = false, - error: DomainError? = null, - errorConverter: ErrorConverter? = null, + error: ModuleError? = null, + errorConverter: ModuleMessageConverter? = null, debounceTextChanges: Long = 400, visualTransformation: VisualTransformation = VisualTransformation.None, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, @@ -79,7 +80,7 @@ private fun OutlinedProgressTextField( placeholder: String = "", isEnabled: Boolean = true, isLoading: Boolean = false, - error: DomainError? = null, + error: ModuleError? = null, debounce: Long = 400, visualTransformation: VisualTransformation = VisualTransformation.None, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, @@ -132,8 +133,8 @@ private fun OutlinedProgressTextField( @Composable private fun AnimatedErrorView( - error: DomainError? = null, - errorConverter: ErrorConverter, + error: ModuleError? = null, + errorConverter: ModuleMessageConverter, ) { AnimatedVisibility( visible = error != null, @@ -141,7 +142,7 @@ private fun AnimatedErrorView( exit = slideOutVertically() + fadeOut(), ) { error?.let { - ErrorView(errorConverter.convertError(it), style = TextStyle(fontSize = 14.sp)) + ErrorView(errorConverter.convert(it), style = TextStyle(fontSize = 14.sp)) } } } @@ -149,20 +150,14 @@ private fun AnimatedErrorView( @Preview @Composable fun OutlinedTextFieldWithErrorTest() { - val converter = remember { - object : ErrorConverter { - override fun convertError(error: DomainError): String { - return "Hello, i'am the error: ${error::class.java.simpleName}" - } - - } - } + val context = LocalContext.current + val converter = remember { ModuleMessageConverter(context) } class SimpleError( override val code: Int = 1, override val message: String = "Error message", override val data: Any? = null, - ) : DomainError + ) : ModuleError val modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/com/tangem/tap/common/moduleMessage/ModuleMessageConverter.kt b/app/src/main/java/com/tangem/tap/common/moduleMessage/ModuleMessageConverter.kt new file mode 100644 index 0000000000..a7247ebe20 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/moduleMessage/ModuleMessageConverter.kt @@ -0,0 +1,24 @@ +package com.tangem.tap.common.moduleMessage + +import android.content.Context +import com.tangem.common.module.ModuleMessage +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.domain.DomainModuleMessage +import com.tangem.tap.common.moduleMessage.domain.DomainMessageConverter + +class ModuleMessageConverter( + private val context: Context +) : ModuleMessageConverter { + + override fun convert(message: ModuleMessage): String { + val convertedMessage = when (message) { + is DomainModuleMessage -> DomainMessageConverter(context).convert(message) + else -> null + } + return convertedMessage ?: convertUnknownMessage(message) + } + + private fun convertUnknownMessage(message: ModuleMessage): String { + return "Unknown message: ${message::class.java.simpleName}" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/DomainErrorConverter.kt b/app/src/main/java/com/tangem/tap/common/moduleMessage/domain/DomainErrorConverters.kt similarity index 52% rename from app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/DomainErrorConverter.kt rename to app/src/main/java/com/tangem/tap/common/moduleMessage/domain/DomainErrorConverters.kt index db6b5aa462..aeb3723a1a 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/DomainErrorConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/moduleMessage/domain/DomainErrorConverters.kt @@ -1,10 +1,9 @@ -package com.tangem.tap.features.tokens.addCustomToken +package com.tangem.tap.common.moduleMessage.domain import android.content.Context +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.domain.AddCustomTokenError import com.tangem.domain.DomainError -import com.tangem.domain.ErrorConverter -import com.tangem.domain.features.addCustomToken.AddCustomTokenError -import com.tangem.domain.features.addCustomToken.AddCustomTokenWarning import com.tangem.wallet.R /** @@ -12,27 +11,23 @@ import com.tangem.wallet.R */ class DomainErrorConverter( private val context: Context -) : ErrorConverter { - - override fun convertError(error: DomainError): String { - val errorMessage = when (error) { - is AddCustomTokenError -> AddCustomTokenConverter(context).convertError(error) - else -> null - } - return errorMessage?.let { it } ?: "Unknown error: ${error::class.java.simpleName}" +) : ModuleMessageConverter { + override fun convert(message: DomainError): String? = when (message) { + is AddCustomTokenError -> AddCustomTokenConverter(context).convert(message) + else -> null } } private class AddCustomTokenConverter( private val context: Context -) : ErrorConverter { +) : ModuleMessageConverter { - override fun convertError(error: DomainError): String { - val customTokenError = (error as? AddCustomTokenError) ?: throw UnsupportedOperationException() + override fun convert(message: DomainError): String? { + val customTokenError = (message as? AddCustomTokenError) ?: throw UnsupportedOperationException() val rawMessage = when (customTokenError) { - AddCustomTokenWarning.PotentialScamToken -> R.string.custom_token_validation_error_not_found - AddCustomTokenWarning.TokenAlreadyAdded -> R.string.custom_token_validation_error_already_added + AddCustomTokenError.Warning.PotentialScamToken -> R.string.custom_token_validation_error_not_found + AddCustomTokenError.Warning.TokenAlreadyAdded -> R.string.custom_token_validation_error_already_added AddCustomTokenError.InvalidContractAddress -> R.string.custom_token_creation_error_invalid_contract_address AddCustomTokenError.NetworkIsNotSelected -> R.string.custom_token_creation_error_network_not_selected AddCustomTokenError.InvalidDerivationPath -> R.string.custom_token_creation_error_invalid_derivation_path @@ -42,10 +37,11 @@ private class AddCustomTokenConverter( AddCustomTokenError.FieldIsEmpty -> R.string.custom_token_creation_error_required_field else -> null } + return when (rawMessage) { is Int -> context.getString(rawMessage) is String -> rawMessage - else -> "Unknown error: ${customTokenError::class.java.simpleName}" + else -> null } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/moduleMessage/domain/DomainMessageConverter.kt b/app/src/main/java/com/tangem/tap/common/moduleMessage/domain/DomainMessageConverter.kt new file mode 100644 index 0000000000..3afb79b219 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/moduleMessage/domain/DomainMessageConverter.kt @@ -0,0 +1,20 @@ +package com.tangem.tap.common.moduleMessage.domain + +import android.content.Context +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.domain.DomainError +import com.tangem.domain.DomainModuleMessage + +/** +[REDACTED_AUTHOR] + */ +class DomainMessageConverter( + private val context: Context +) : ModuleMessageConverter { + override fun convert(message: DomainModuleMessage): String? { + return when (message) { + is DomainError -> DomainErrorConverter(context).convert(message) + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt index 83641420f3..ea27e5137f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/AddCustomTokenScreen.kt @@ -13,11 +13,9 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.tangem.domain.ErrorConverter +import com.tangem.domain.AddCustomTokenError import com.tangem.domain.common.form.DataField import com.tangem.domain.common.form.FieldId -import com.tangem.domain.features.addCustomToken.AddCustomTokenError -import com.tangem.domain.features.addCustomToken.AddCustomTokenWarning import com.tangem.domain.features.addCustomToken.CustomTokenFieldId.* import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState @@ -27,7 +25,7 @@ import com.tangem.domain.redux.domainStore import com.tangem.tap.common.compose.ComposeDialogManager import com.tangem.tap.common.compose.ToggledRippleTheme import com.tangem.tap.common.compose.keyboardAsState -import com.tangem.tap.features.tokens.addCustomToken.DomainErrorConverter +import com.tangem.tap.common.moduleMessage.ModuleMessageConverter import com.tangem.wallet.R /** @@ -82,7 +80,7 @@ fun AddCustomTokenScreen(state: MutableState) { @Composable private fun FormFields(state: MutableState) { val context = LocalContext.current - val errorConverter = remember { DomainErrorConverter(context) } + val errorConverter = remember { ModuleMessageConverter(context) } val stateValue = state.value stateValue.form.fieldList.forEach { field -> @@ -99,11 +97,11 @@ private fun FormFields(state: MutableState) { } @Composable -fun Warnings(warnings: List) { +fun Warnings(warnings: List) { if (warnings.isEmpty()) return val context = LocalContext.current - val warningConverter = remember { DomainErrorConverter(context) } + val warningConverter = remember { ModuleMessageConverter(context) } Column { warnings.forEachIndexed { index, item -> @@ -120,7 +118,7 @@ fun Warnings(warnings: List) { ) { Text( modifier = Modifier.padding(16.dp), - text = warningConverter.convertError(item), + text = warningConverter.convert(item), color = colorResource(id = R.color.white), fontSize = 14.sp ) @@ -172,14 +170,14 @@ private fun AddCustomTokenFab( data class ScreenFieldData( val field: DataField<*>, val error: AddCustomTokenError?, - val errorConverter: ErrorConverter, + val errorConverter: ModuleMessageConverter, val viewState: ViewStates.TokenField ) { companion object { fun fromState( field: DataField<*>, state: AddCustomTokenState, - errorConverter: DomainErrorConverter + errorConverter: ModuleMessageConverter ): ScreenFieldData { return ScreenFieldData( field = field, diff --git a/common/.gitignore b/common/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/common/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000000..0412225730 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'java-library' + id 'org.jetbrains.kotlin.jvm' +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} \ No newline at end of file diff --git a/common/src/main/java/com/tangem/common/Validator.kt b/common/src/main/java/com/tangem/common/Validator.kt new file mode 100644 index 0000000000..8654e9d07e --- /dev/null +++ b/common/src/main/java/com/tangem/common/Validator.kt @@ -0,0 +1,8 @@ +package com.tangem.common + +/** +[REDACTED_AUTHOR] + */ +interface Validator { + fun validate(data: Data? = null): Error? +} \ No newline at end of file diff --git a/common/src/main/java/com/tangem/common/module/ModuleException.kt b/common/src/main/java/com/tangem/common/module/ModuleException.kt new file mode 100644 index 0000000000..233d47f942 --- /dev/null +++ b/common/src/main/java/com/tangem/common/module/ModuleException.kt @@ -0,0 +1,14 @@ +package com.tangem.common.module + +/** +[REDACTED_AUTHOR] + * A module exception + */ +interface ModuleException { + val message: String +} + +/** + * An exception marked as FbConsumeException should be submitted to Firebase.Crashlytics as a non-fatal issue. + */ +interface FbConsumeException \ No newline at end of file diff --git a/common/src/main/java/com/tangem/common/module/ModuleMessage.kt b/common/src/main/java/com/tangem/common/module/ModuleMessage.kt new file mode 100644 index 0000000000..240e7c8759 --- /dev/null +++ b/common/src/main/java/com/tangem/common/module/ModuleMessage.kt @@ -0,0 +1,22 @@ +package com.tangem.common.module + +/** +[REDACTED_AUTHOR] + * The base object for communication between modules + */ +interface ModuleMessage + +interface ModuleMessageConverter { + fun convert(message: ModuleMessage): R +} + +/** + * @property code describes what feature is the error coming from + * @property message the error description + * @property data any data that can help in the part where this error is being handled + */ +interface ModuleError : ModuleMessage { + val code: Int + val message: String + val data: Any? +} \ No newline at end of file diff --git a/domain/build.gradle b/domain/build.gradle index f64927d8a7..8180476f6b 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -47,13 +47,14 @@ android { dependencies { implementation implementation(project(path: ':network')) + implementation implementation(project(path: ':common')) // Tangem sdk's implementation 'com.tangem:blockchain:develop-71' implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142' implementation 'com.tangem.tangem-sdk-kotlin:android:develop-142' - // Kotlin + // Kotlin coroutines implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' // State management diff --git a/domain/src/main/java/com/tangem/domain/DomainError.kt b/domain/src/main/java/com/tangem/domain/DomainError.kt index 7f6b14c1ed..1f923c0c90 100644 --- a/domain/src/main/java/com/tangem/domain/DomainError.kt +++ b/domain/src/main/java/com/tangem/domain/DomainError.kt @@ -1,29 +1,42 @@ package com.tangem.domain +import com.tangem.common.module.ModuleError +import com.tangem.common.module.ModuleMessage + /** [REDACTED_AUTHOR] - * @property code describes what feature is the error coming from - * @property message the error description - * @property data any data that can help in the part where this error is being handled + * All DomainError descendants must use their own range of codes, but no more than 999 error codes for each. */ -interface DomainError : DomainMessage { - val code: Int - val message: String - val data: Any? -} +sealed interface DomainModuleMessage : ModuleMessage -open class AnError( +sealed class DomainError( override val code: Int, override val message: String, - override val data: Any? = null, -) : DomainError + override val data: Any?, +) : DomainModuleMessage, ModuleError { -interface ErrorConverter { - fun convertError(error: DomainError): T + companion object { + const val CODE_ADD_CUSTOM_TOKEN = 1000 + } } -interface Validator { - fun validate(data: Data? = null): Error? -} +sealed class AddCustomTokenError( + subCode: Int = 0 +) : DomainError(CODE_ADD_CUSTOM_TOKEN + subCode, this::class.java.simpleName, null) { -const val ERROR_CODE_ADD_CUSTOM_TOKEN = 100 \ No newline at end of file + object FieldIsEmpty : AddCustomTokenError() + object FieldIsNotEmpty : AddCustomTokenError() + object InvalidContractAddress : AddCustomTokenError() + object NetworkIsNotSelected : AddCustomTokenError() + object InvalidDecimalsCount : AddCustomTokenError() + object InvalidDerivationPath : AddCustomTokenError() + + sealed class Network : AddCustomTokenError() { + object CheckAddressRequestError : Network() + } + + sealed class Warning : AddCustomTokenError() { + object PotentialScamToken : Warning() + object TokenAlreadyAdded : Warning() + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/DomainException.kt b/domain/src/main/java/com/tangem/domain/DomainException.kt index f137262717..b6fc362990 100644 --- a/domain/src/main/java/com/tangem/domain/DomainException.kt +++ b/domain/src/main/java/com/tangem/domain/DomainException.kt @@ -1,17 +1,19 @@ package com.tangem.domain +import com.tangem.common.module.FbConsumeException +import com.tangem.common.module.ModuleException + /** [REDACTED_AUTHOR] - * Must be handled by the module or sent to Crashlytics */ -interface DomainInternalException +sealed class AddCustomTokenException(override val message: String) : Throwable(message), ModuleException { -sealed class DomainException(message: String?) : Throwable(message), DomainInternalException { - data class SelectTokeNetworkException(val networkId: String) : DomainException( + data class SelectTokeNetworkException(val networkId: String) : AddCustomTokenException( "Unknown network [$networkId] should not be included in the network selection dialog." - ) + ), FbConsumeException - data class UnAppropriateInitializationException(val of: String, val info: String? = null) : DomainException( - "The [$of], must be properly initialized. Info []" - ) + data class UnAppropriateInitializationException( + val of: String, + val info: String? = null + ) : AddCustomTokenException("The [$of], must be properly initialized. Info [$info]") } \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/DomainMessage.kt b/domain/src/main/java/com/tangem/domain/DomainMessage.kt deleted file mode 100644 index 5ff7266ab9..0000000000 --- a/domain/src/main/java/com/tangem/domain/DomainMessage.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.domain - -/** -[REDACTED_AUTHOR] - */ -sealed interface DomainMessage - -sealed interface DomainNotification : DomainMessage { - interface Toast : DomainNotification {} - - interface Snackbar : DomainNotification {} - - interface Dialog : DomainNotification {} - -} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt b/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt index 712fa36bd3..431b0ff2af 100644 --- a/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt +++ b/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt @@ -2,8 +2,8 @@ package com.tangem.domain.common.form import com.tangem.blockchain.blockchains.ethereum.EthereumAddressService import com.tangem.blockchain.common.Blockchain -import com.tangem.domain.Validator -import com.tangem.domain.features.addCustomToken.AddCustomTokenError +import com.tangem.common.Validator +import com.tangem.domain.AddCustomTokenError /** [REDACTED_AUTHOR] diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/Errors.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/Errors.kt deleted file mode 100644 index ebf097d964..0000000000 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/Errors.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.domain.features.addCustomToken - -import com.tangem.domain.AnError -import com.tangem.domain.ERROR_CODE_ADD_CUSTOM_TOKEN - -/** -[REDACTED_AUTHOR] - */ -sealed class AddCustomTokenError : AnError(ERROR_CODE_ADD_CUSTOM_TOKEN, "Add custom token - error") { - object FieldIsEmpty : AddCustomTokenError() - object FieldIsNotEmpty : AddCustomTokenError() - object InvalidContractAddress : AddCustomTokenError() - object NetworkIsNotSelected : AddCustomTokenError() - object InvalidDecimalsCount : AddCustomTokenError() - object InvalidDerivationPath : AddCustomTokenError() - - sealed class Network : AddCustomTokenWarning() { - object CheckAddressRequestError : Network() - } -} - -sealed class AddCustomTokenWarning : AddCustomTokenError() { - object PotentialScamToken : AddCustomTokenWarning() - object TokenAlreadyAdded : AddCustomTokenWarning() -} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt index dc832d367a..f1eadfeab5 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenAction.kt @@ -2,11 +2,10 @@ package com.tangem.domain.features.addCustomToken.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle +import com.tangem.domain.AddCustomTokenError import com.tangem.domain.DomainWrapped import com.tangem.domain.common.form.Field import com.tangem.domain.common.form.FieldId -import com.tangem.domain.features.addCustomToken.AddCustomTokenError -import com.tangem.domain.features.addCustomToken.AddCustomTokenWarning import com.tangem.domain.features.addCustomToken.CustomCurrency import com.tangem.domain.features.addCustomToken.CustomTokenFieldId import org.rekotlin.Action @@ -47,9 +46,12 @@ sealed class AddCustomTokenAction : Action { // warnings sealed class Warning : AddCustomTokenAction() { - data class Add(val warnings: Set) : Warning() - data class Remove(val warnings: Set) : Warning() - data class Replace(val remove: Set, val add: Set) : Warning() + data class Add(val warnings: Set) : Warning() + data class Remove(val warnings: Set) : Warning() + data class Replace( + val remove: Set, + val add: Set + ) : Warning() } // To change the screenState diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 799ceaf58f..af0bdd7525 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -5,8 +5,11 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle import com.tangem.common.extensions.guard import com.tangem.common.services.Result +import com.tangem.domain.AddCustomTokenError +import com.tangem.domain.AddCustomTokenError.Warning.PotentialScamToken +import com.tangem.domain.AddCustomTokenError.Warning.TokenAlreadyAdded +import com.tangem.domain.AddCustomTokenException import com.tangem.domain.DomainDialog -import com.tangem.domain.DomainException import com.tangem.domain.DomainWrapped import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.extensions.fromNetworkId @@ -145,9 +148,9 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT private suspend fun updateWarningAlreadyAdded(isInAppSavedList: Boolean) { if (isInAppSavedList) { - AddCustomTokenWarning.TokenAlreadyAdded.add() + TokenAlreadyAdded.add() } else { - AddCustomTokenWarning.TokenAlreadyAdded.remove() + TokenAlreadyAdded.remove() } } @@ -170,7 +173,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT val result = when (foundTokensResult) { is Result.Success -> foundTokensResult.data is Result.Failure -> { -// val warning = AddCustomTokenWarning.Network.CheckAddressRequestError +// val warning = Warning.Network.CheckAddressRequestError // dispatchOnMain(Warning.Add(setOf(warning))) emptyList() } @@ -182,8 +185,8 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT private suspend fun manageFoundTokenChanges(foundTokens: List) { if (foundTokens.isEmpty()) { // token not found - it's completely custom - AddCustomTokenWarning.TokenAlreadyAdded.remove() - AddCustomTokenWarning.PotentialScamToken.add() + TokenAlreadyAdded.remove() + PotentialScamToken.add() dispatchOnMain(SetFoundTokenId(null)) clearTokenFields() @@ -208,33 +211,33 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT if (isInAppSavedTokens) { lockTokenFields() lockAddButton() - AddCustomTokenWarning.PotentialScamToken.replace(AddCustomTokenWarning.TokenAlreadyAdded) + PotentialScamToken.replace(TokenAlreadyAdded) } else { // not in the saved tokens list if (singleTokenContract.active) { lockTokenFields() unlockAddButton() if (hubState.derivationPathIsSelected()) { - AddCustomTokenWarning.PotentialScamToken.add() + PotentialScamToken.add() } else { - AddCustomTokenWarning.TokenAlreadyAdded.remove() - AddCustomTokenWarning.PotentialScamToken.remove() + TokenAlreadyAdded.remove() + PotentialScamToken.remove() } } else { unlockAddButton() - AddCustomTokenWarning.PotentialScamToken.add() + PotentialScamToken.add() } } } else -> { - AddCustomTokenWarning.PotentialScamToken.replace(AddCustomTokenWarning.TokenAlreadyAdded) + PotentialScamToken.replace(TokenAlreadyAdded) val dialog = DomainDialog.SelectTokenDialog( items = foundToken.contracts, networkIdConverter = { networkId -> val blockchain = Blockchain.fromNetworkId(networkId) if (blockchain == null || blockchain == Blockchain.Unknown) { - throw DomainException.SelectTokeNetworkException(networkId) + throw AddCustomTokenException.SelectTokeNetworkException(networkId) } hubState.blockchainToName(blockchain) ?: "" }, @@ -253,8 +256,8 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT } private suspend fun replaceWarnings( - warningsAdd: MutableSet = mutableSetOf(), - warningsRemove: MutableSet = mutableSetOf(), + warningsAdd: MutableSet = mutableSetOf(), + warningsRemove: MutableSet = mutableSetOf(), ) { if (warningsAdd.isNotEmpty() || warningsRemove.isNotEmpty()) { dispatchOnMain(Warning.Replace(warningsRemove.toSet(), warningsAdd.toSet())) @@ -263,7 +266,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT private suspend fun updateAddButton() { val state = hubState - if (state.warnings.contains(AddCustomTokenWarning.TokenAlreadyAdded)) { + if (state.warnings.contains(TokenAlreadyAdded)) { lockAddButton() return } @@ -483,19 +486,19 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT dispatchOnMain(action) } - private suspend fun AddCustomTokenWarning.add() { + private suspend fun AddCustomTokenError.Warning.add() { dispatchOnMain(Warning.Add(setOf(this))) } - private suspend fun AddCustomTokenWarning.remove() { + private suspend fun AddCustomTokenError.Warning.remove() { dispatchOnMain(Warning.Remove(setOf(this))) } - private suspend fun AddCustomTokenWarning.replace(to: AddCustomTokenWarning) { + private suspend fun AddCustomTokenError.Warning.replace(to: AddCustomTokenError.Warning) { dispatchOnMain(Warning.Replace(setOf(this), setOf(to))) } -// private suspend fun AddCustomTokenWarning.replace(replace: Boolean, to: AddCustomTokenWarning) { +// private suspend fun Warning.replace(replace: Boolean, to: Warning) { // if (replace) dispatchOnMain(Warning.Replace(setOf(this), setOf(to))) // } @@ -653,7 +656,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT @Throws private fun throwUnAppropriateInitialization(objName: String) { - throw DomainException.UnAppropriateInitializationException( + throw AddCustomTokenException.UnAppropriateInitializationException( "AddCustomTokenHub", "$objName must be not NULL" ) } diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index 82e3b9c068..1d359780bd 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -2,6 +2,7 @@ package com.tangem.domain.features.addCustomToken.redux import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationStyle +import com.tangem.domain.AddCustomTokenError import com.tangem.domain.DomainWrapped import com.tangem.domain.common.form.* import com.tangem.domain.features.addCustomToken.* @@ -16,7 +17,7 @@ data class AddCustomTokenState( val formValidators: Map> = createFormValidators(), val formErrors: Map = emptyMap(), val tokenId: String? = null, - val warnings: Set = emptySet(), + val warnings: Set = emptySet(), val screenState: ScreenState = createInitialScreenState(), val tangemTechServiceManager: AddCustomTokenService? = null ) : StateType { diff --git a/network/build.gradle b/network/build.gradle index f89fb54c38..b90ff59980 100644 --- a/network/build.gradle +++ b/network/build.gradle @@ -9,9 +9,17 @@ java { } dependencies { + implementation implementation(project(path: ':common')) + // Tangem sdk's implementation 'com.tangem.tangem-sdk-kotlin:core:develop-142' + // Kotlin coroutines + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' + + // Logs + implementation 'com.jakewharton.timber:timber:4.7.1' + // Network implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3")) implementation("com.squareup.okhttp3:okhttp") diff --git a/settings.gradle b/settings.gradle index a6c2d48bed..9b33b9462c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include ':app' include ':domain' include ':network' +include ':common'