diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index ef357f782f..d3fe7eacd2 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -17,6 +17,9 @@ import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.ui.dialog.CreateWalletInterruptDialog import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.NoFundsForActivationDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.RegistrationErrorDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AddMoreBackupCardsDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BackupInProgressDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog @@ -126,6 +129,8 @@ class DialogManager : StoreSubscriber { is BackupDialog.BackupInProgress -> BackupInProgressDialog.create(context) is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context) is BackupDialog.ConfirmDiscardingBackup -> ConfirmDiscardingBackupDialog.create(context) + is SaltPayDialog.NoFundsForActivation -> NoFundsForActivationDialog.create(context) + is SaltPayDialog.RegistrationError -> RegistrationErrorDialog.create(context, state.dialog) is WalletDialog.CurrencySelectionDialog -> CurrencySelectionDialog.create(state.dialog, context) is WalletDialog.ChooseTradeActionDialog -> diff --git a/app/src/main/java/com/tangem/tap/common/Handler.kt b/app/src/main/java/com/tangem/tap/common/Handler.kt index f36d4d1541..37b39734cb 100644 --- a/app/src/main/java/com/tangem/tap/common/Handler.kt +++ b/app/src/main/java/com/tangem/tap/common/Handler.kt @@ -15,6 +15,10 @@ fun postBackground(ms: Long = 0, func: Runnable) { if (ms == 0L) backgroundHandler.post { func.run() } else backgroundHandler.postDelayed(func, ms) } +fun postUiDelayBg(ms: Long, func: Runnable) { + backgroundHandler.postDelayed({ uiHandler.post(func) }, ms) +} + fun post(ms: Long = 0, func: Runnable) { if (ms == 0L) { func.run() diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/ConvertedMessage.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/ConvertedMessage.kt new file mode 100644 index 0000000000..a8add4f2a5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/ConvertedMessage.kt @@ -0,0 +1,32 @@ +package com.tangem.tap.domain.moduleMessage + +/** +[REDACTED_AUTHOR] + * Base interface for conversion outputs from ModuleMessageConverter + */ +interface ConvertedMessage { + val message: String +} + +/** + * Dialog message used to construct a android.Dialog + */ +interface DialogMessage : ConvertedMessage { + val title: String + override val message: String + val onPositive: String? + val onNegative: String? + val onNeutral: String? +} + +data class ConvertedStringMessage( + override val message: String, +) : ConvertedMessage + +data class ConvertedDialogMessage( + override val title: String, + override val message: String, + override val onPositive: String? = null, + override val onNegative: String? = null, + override val onNeutral: String? = null, +) : DialogMessage \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/ModuleMessageConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/ModuleMessageConverter.kt new file mode 100644 index 0000000000..7c665e5cdd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/ModuleMessageConverter.kt @@ -0,0 +1,27 @@ +package com.tangem.tap.domain.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.domain.moduleMessage.domain.DomainMessageConverter +import com.tangem.tap.domain.moduleMessage.saltPay.SaltPayMessageConverter +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayModuleMessage + +class ModuleMessageConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: ModuleMessage): ConvertedMessage { + val convertedMessage = when (message) { + is DomainModuleMessage -> DomainMessageConverter(context).convert(message) + is SaltPayModuleMessage -> SaltPayMessageConverter(context).convert(message) + else -> null + } + return convertedMessage ?: convertUnknownMessage(message) + } + + private fun convertUnknownMessage(message: ModuleMessage): ConvertedMessage { + return ConvertedStringMessage("Unknown message: ${message::class.java.simpleName}") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/DomainMessageConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/DomainMessageConverter.kt new file mode 100644 index 0000000000..67c58be34a --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/DomainMessageConverter.kt @@ -0,0 +1,34 @@ +package com.tangem.tap.domain.moduleMessage.domain + +import android.content.Context +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.domain.AddCustomTokenError +import com.tangem.domain.DomainModuleError +import com.tangem.domain.DomainModuleMessage +import com.tangem.tap.domain.moduleMessage.ConvertedMessage +import com.tangem.tap.domain.moduleMessage.domain.converter.AddCustomTokenErrorConverter + +/** +[REDACTED_AUTHOR] + */ +class DomainMessageConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: DomainModuleMessage): ConvertedMessage? { + return when (message) { + is DomainModuleError -> DomainErrorConverter(context).convert(message) + else -> null + } + } +} + +class DomainErrorConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: DomainModuleError): ConvertedMessage? = when (message) { + is AddCustomTokenError -> AddCustomTokenErrorConverter(context).convert(message) + else -> null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt new file mode 100644 index 0000000000..66e41dc48e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt @@ -0,0 +1,41 @@ +package com.tangem.tap.domain.moduleMessage.domain.converter + +import android.content.Context +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.domain.AddCustomTokenError +import com.tangem.domain.DomainModuleError +import com.tangem.tap.domain.moduleMessage.ConvertedMessage +import com.tangem.tap.domain.moduleMessage.ConvertedStringMessage +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +internal class AddCustomTokenErrorConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: DomainModuleError): ConvertedMessage? { + val customTokenError = (message as? AddCustomTokenError) ?: throw UnsupportedOperationException() + + val rawMessage = when (customTokenError) { + AddCustomTokenError.Warning.PotentialScamToken -> R.string.custom_token_validation_error_not_found + AddCustomTokenError.Warning.TokenAlreadyAdded -> R.string.custom_token_validation_error_already_added + AddCustomTokenError.Warning.UnsupportedSolanaToken -> R.string.alert_manage_tokens_unsupported_message + 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 + AddCustomTokenError.InvalidDecimalsCount -> { + context.getString(R.string.custom_token_creation_error_wrong_decimals, 30) + } + AddCustomTokenError.FieldIsEmpty -> R.string.custom_token_creation_error_required_field + else -> null + } + + return when (rawMessage) { + is Int -> ConvertedStringMessage(context.getString(rawMessage)) + is String -> ConvertedStringMessage(rawMessage) + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt new file mode 100644 index 0000000000..6ad14c42b0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt @@ -0,0 +1,34 @@ +package com.tangem.tap.domain.moduleMessage.saltPay + +import android.content.Context +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.tap.domain.moduleMessage.ConvertedMessage +import com.tangem.tap.domain.moduleMessage.saltPay.converter.SaltPayRegistrationErrorConverter +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayModuleError +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayModuleMessage +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayRegistrationError + +/** +[REDACTED_AUTHOR] + */ +class SaltPayMessageConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: SaltPayModuleMessage): ConvertedMessage? { + return when (message) { + is SaltPayModuleError -> SaltPayErrorConverter(context).convert(message) + else -> null + } + } +} + +class SaltPayErrorConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: SaltPayModuleError): ConvertedMessage? = when (message) { + is SaltPayRegistrationError -> SaltPayRegistrationErrorConverter(context).convert(message) + else -> null + } +} diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayRegistrationErrorConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayRegistrationErrorConverter.kt new file mode 100644 index 0000000000..ecf2f8a28f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayRegistrationErrorConverter.kt @@ -0,0 +1,46 @@ +package com.tangem.tap.domain.moduleMessage.saltPay.converter + +import android.content.Context +import com.tangem.common.module.ModuleMessageConverter +import com.tangem.tap.domain.moduleMessage.ConvertedDialogMessage +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayRegistrationError +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +internal class SaltPayRegistrationErrorConverter( + private val context: Context, +) : ModuleMessageConverter { + + override fun convert(message: SaltPayRegistrationError): ConvertedDialogMessage? { + val saltPayError = (message as? SaltPayRegistrationError) ?: throw UnsupportedOperationException() + + val dialogMessage = when (saltPayError) { + SaltPayRegistrationError.NoGas -> { + ConvertedDialogMessage( + title = context.getString(R.string.saltpay_error_no_gas_title), + message = context.getString(R.string.saltpay_error_no_gas_message), + ) + } + SaltPayRegistrationError.EmptyBackupCardScanned -> { + ConvertedDialogMessage( + title = context.getString(R.string.saltpay_error_empty_backup_title), + message = context.getString(R.string.saltpay_error_empty_backup_message), + ) + } + SaltPayRegistrationError.WeakPin -> { + ConvertedDialogMessage( + title = context.getString(R.string.saltpay_error_pin_weak_title), + message = context.getString(R.string.saltpay_error_pin_weak_message), + ) + } + else -> ConvertedDialogMessage( + title = context.getString(R.string.common_error), + message = saltPayError::class.java.simpleName, + ) + } + + return dialogMessage + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/NoFundsForActivationDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/NoFundsForActivationDialog.kt new file mode 100644 index 0000000000..fde8f9637d --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/NoFundsForActivationDialog.kt @@ -0,0 +1,33 @@ +package com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog + +import android.app.Dialog +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.tangem.tap.common.feedback.SupportInfo +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.store +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +class NoFundsForActivationDialog { + companion object { + fun create(context: Context): Dialog { + return AlertDialog.Builder(context).apply { + setTitle(R.string.saltpay_error_no_gas_title) + setMessage(R.string.saltpay_error_no_gas_message) + //TODO: SaltPay: change onboarding_supplement_button_kyc_waiting -> to appropriate string + setPositiveButton(R.string.onboarding_supplement_button_kyc_waiting) { _, _ -> + store.dispatch(GlobalAction.OpenChat(SupportInfo())) + } + setNegativeButton(R.string.common_cancel) { _, _ -> + } + setOnDismissListener { + store.dispatch(GlobalAction.HideDialog) + } + setCancelable(false) + }.create() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/RegistrationErrorDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/RegistrationErrorDialog.kt new file mode 100644 index 0000000000..f7ddfbea66 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/RegistrationErrorDialog.kt @@ -0,0 +1,33 @@ +package com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog + +import android.app.Dialog +import android.content.Context +import androidx.appcompat.app.AlertDialog +import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.domain.moduleMessage.ConvertedDialogMessage +import com.tangem.tap.domain.moduleMessage.saltPay.SaltPayErrorConverter +import com.tangem.tap.store +import com.tangem.wallet.R + +/** +[REDACTED_AUTHOR] + */ +class RegistrationErrorDialog { + companion object { + fun create(context: Context, dialog: SaltPayDialog.RegistrationError): Dialog { + val convertedMessage = SaltPayErrorConverter(context).convert(dialog.error) as ConvertedDialogMessage + + return AlertDialog.Builder(context).apply { + setTitle(convertedMessage.title) + setMessage(convertedMessage.message) + setPositiveButton(R.string.common_ok) { _, _ -> + store.dispatch(GlobalAction.HideDialog) + } + setOnDismissListener { + store.dispatch(GlobalAction.HideDialog) + } + setCancelable(false) + }.create() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt new file mode 100644 index 0000000000..5bd2e1aac0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog + +import com.tangem.tap.common.redux.StateDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayRegistrationError + +/** +[REDACTED_AUTHOR] + */ +sealed class SaltPayDialog : StateDialog { + object NoFundsForActivation : SaltPayDialog() + data class RegistrationError(val error: SaltPayRegistrationError) : SaltPayDialog() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt new file mode 100644 index 0000000000..1820c2c6e9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/message/SaltPayModuleMessage.kt @@ -0,0 +1,45 @@ +package com.tangem.tap.features.onboarding.products.wallet.saltPay.message + +import com.tangem.common.module.ModuleError +import com.tangem.common.module.ModuleErrorCode +import com.tangem.common.module.ModuleMessage + +sealed interface SaltPayModuleMessage : ModuleMessage + +sealed class SaltPayModuleError( + subCode: Int, + override val message: String, + override val data: Any? = null, +) : SaltPayModuleMessage, ModuleError() { + override val code: Int = ModuleErrorCode.SALT_PAY + subCode + + companion object { + // base code used for all errors in the module + internal const val ERROR_CODE_REGISTRATION = 100 +// const val CODE_ANY_OTHER = 200..299, 300..399 etc + } +} + +sealed class SaltPayRegistrationError( + subCode: Int, + message: String? = null, + override val data: Any? = null, +) : SaltPayModuleError( + subCode = ERROR_CODE_REGISTRATION + subCode, + message = message ?: this::class.java.simpleName, +) { + object Unknown : SaltPayRegistrationError(4) + object Empty : SaltPayRegistrationError(4) + object FailedToMakeTxData : SaltPayRegistrationError(1) + object FailedToSendTx : SaltPayRegistrationError(2) + object NeedPin : SaltPayRegistrationError(3) + object NoGas : SaltPayRegistrationError(5) + object EmptyResponse : SaltPayRegistrationError(6) + object Card : SaltPayRegistrationError(7) + object CardNotFound : SaltPayRegistrationError(8) + object CardDisabled : SaltPayRegistrationError(9) + object CardNotPassed : SaltPayRegistrationError(10) + object EmptyDynamicAttestResponse : SaltPayRegistrationError(11) + object EmptyBackupCardScanned : SaltPayRegistrationError(12) + object WeakPin : SaltPayRegistrationError(13) +} \ No newline at end of file