Updated on 2026-08-14
This commit is contained in:
parent
11511d36dd
commit
28b4c29bef
27 changed files with 278 additions and 84 deletions
|
|
@ -0,0 +1,56 @@
|
|||
package com.tangem.common.ui.account
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
|
||||
/**
|
||||
* Represents a user model (UM) for an [AccountName] in the UI layer.
|
||||
* This sealed interface provides a way to handle different types of account names.
|
||||
*/
|
||||
@Immutable
|
||||
sealed interface AccountNameUM {
|
||||
|
||||
/** The textual representation of the account name */
|
||||
val value: TextReference
|
||||
|
||||
/**
|
||||
* Represents the default main account name.
|
||||
* If the user renames the main account, it will be converted to a [Custom] account name.
|
||||
*/
|
||||
data object DefaultMain : AccountNameUM {
|
||||
|
||||
override val value: TextReference = resourceReference(R.string.account_main_account_title)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom account name provided by the user
|
||||
*
|
||||
* @property raw the raw string value of the custom account name
|
||||
*/
|
||||
class Custom(internal val raw: String) : AccountNameUM {
|
||||
|
||||
override val value: TextReference = stringReference(value = raw)
|
||||
}
|
||||
}
|
||||
|
||||
/** Extension function to convert a domain model [AccountName] to its corresponding UI model [AccountNameUM] */
|
||||
fun AccountName.toUM(): AccountNameUM {
|
||||
return when (this) {
|
||||
is AccountName.Custom -> AccountNameUM.Custom(raw = value)
|
||||
AccountName.DefaultMain -> AccountNameUM.DefaultMain
|
||||
}
|
||||
}
|
||||
|
||||
/** Extension function to convert a UI model [AccountNameUM] to its corresponding domain model [AccountName] */
|
||||
fun AccountNameUM.toDomain(): Either<AccountName.Error, AccountName> = either {
|
||||
when (this@toDomain) {
|
||||
is AccountNameUM.Custom -> AccountName(value = raw).bind()
|
||||
AccountNameUM.DefaultMain -> AccountName.DefaultMain
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
|||
@JsonClass(generateAdapter = true)
|
||||
data class WalletAccountDTO(
|
||||
@Json(name = "id") val id: String,
|
||||
@Json(name = "name") val name: String,
|
||||
@Json(name = "name") val name: String?,
|
||||
@Json(name = "derivation") val derivationIndex: Int,
|
||||
@Json(name = "icon") val icon: String,
|
||||
@Json(name = "iconColor") val iconColor: String,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.data.account.converter
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
@ -14,12 +13,6 @@ internal fun String.toAccountId(userWalletId: UserWalletId): AccountId {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun String.toAccountName(): AccountName {
|
||||
return AccountName(value = this).getOrElse {
|
||||
error("Unable to create AccountName from value: $this. Cause: $it")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun WalletAccountDTO.toIcon(): CryptoPortfolioIcon {
|
||||
return CryptoPortfolioIconConverter.convert(
|
||||
value = CryptoPortfolioIconConverter.DataModel(icon = icon, color = iconColor),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
/**
|
||||
* A converter for transforming [AccountName] domain models into their string representations.
|
||||
* This is used to handle the conversion logic between the domain layer and other layers.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object AccountNameConverter : TwoWayConverter<AccountName, String?> {
|
||||
|
||||
override fun convert(value: AccountName): String? {
|
||||
return when (value) {
|
||||
is AccountName.Custom -> value.value
|
||||
AccountName.DefaultMain -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertBack(value: String?): AccountName {
|
||||
return if (value == null) {
|
||||
AccountName.DefaultMain
|
||||
} else {
|
||||
AccountName(value = value).getOrElse {
|
||||
error("Unable to create AccountName from value: $value. Cause: $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ internal class ArchivedAccountConverter(
|
|||
override fun convert(value: WalletAccountDTO): ArchivedAccount {
|
||||
return ArchivedAccount(
|
||||
accountId = value.id.toAccountId(userWalletId = userWalletId),
|
||||
name = value.name.toAccountName(),
|
||||
name = AccountNameConverter.convertBack(value = value.name),
|
||||
icon = value.toIcon(),
|
||||
derivationIndex = value.derivationIndex.toDerivationIndex(),
|
||||
tokensCount = value.totalTokens ?: error("Total tokens should not be null"),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ internal class CryptoPortfolioConverter @AssistedInject constructor(
|
|||
|
||||
return Account.CryptoPortfolio(
|
||||
accountId = value.id.toAccountId(userWallet.walletId),
|
||||
accountName = value.name.toAccountName(),
|
||||
accountName = AccountNameConverter.convertBack(value = value.name),
|
||||
icon = value.toIcon(),
|
||||
derivationIndex = value.derivationIndex.toDerivationIndex(),
|
||||
cryptoCurrencies = if (tokens.isNotEmpty()) {
|
||||
|
|
@ -46,7 +46,7 @@ internal class CryptoPortfolioConverter @AssistedInject constructor(
|
|||
override fun convertBack(value: Account.CryptoPortfolio): WalletAccountDTO {
|
||||
return WalletAccountDTO(
|
||||
id = value.accountId.value,
|
||||
name = value.accountName.value,
|
||||
name = AccountNameConverter.convert(value = value.accountName),
|
||||
derivationIndex = value.derivationIndex.value,
|
||||
icon = value.icon.value.name,
|
||||
iconColor = value.icon.color.name,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ internal object SaveWalletAccountsResponseConverter : Converter<AccountList, Sav
|
|||
private fun toDTO(account: Account.CryptoPortfolio): WalletAccountDTO {
|
||||
return WalletAccountDTO(
|
||||
id = account.accountId.value,
|
||||
name = account.accountName.value,
|
||||
name = AccountNameConverter.convert(value = account.accountName),
|
||||
derivationIndex = account.derivationIndex.value,
|
||||
icon = account.icon.value.name,
|
||||
iconColor = account.icon.color.name,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.account.models.AccountList
|
|||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ internal fun createWalletAccountDTO(
|
|||
|
||||
return WalletAccountDTO(
|
||||
id = accountId ?: mainAccount.accountId.value,
|
||||
name = accountName ?: mainAccount.accountName.value,
|
||||
name = accountName ?: (mainAccount.accountName as? AccountName.Custom)?.value,
|
||||
derivationIndex = derivationIndex ?: mainAccount.derivationIndex.value,
|
||||
icon = icon ?: mainAccount.icon.value.name,
|
||||
iconColor = iconColor ?: mainAccount.icon.color.name,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class AccountNameConverterTest {
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: ConvertModel) {
|
||||
// Act
|
||||
val actual = AccountNameConverter.convert(value = model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertModel> {
|
||||
return listOf(
|
||||
ConvertModel(
|
||||
value = AccountName.Custom("MyAccount").getOrNull()!!,
|
||||
expected = "MyAccount",
|
||||
),
|
||||
ConvertModel(value = AccountName.DefaultMain, expected = null),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ConvertBack {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convertBack(model: ConvertBackModel) {
|
||||
// Act
|
||||
val actual = AccountNameConverter.convertBack(value = model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertBackModel> {
|
||||
return listOf(
|
||||
ConvertBackModel(value = "MyAccount", expected = AccountName.Custom("MyAccount").getOrNull()!!),
|
||||
ConvertBackModel(value = null, expected = AccountName.DefaultMain),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertModel(val value: AccountName, val expected: String?)
|
||||
|
||||
data class ConvertBackModel(val value: String?, val expected: AccountName)
|
||||
}
|
||||
|
|
@ -54,6 +54,12 @@ class ArchivedAccountConverterTest {
|
|||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(name = null),
|
||||
expected = Result.success(
|
||||
createDomain().copy(name = AccountName.DefaultMain),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(name = ""),
|
||||
expected = Result.failure(
|
||||
|
|
@ -104,7 +110,7 @@ class ArchivedAccountConverterTest {
|
|||
|
||||
private fun createDTO(
|
||||
accountId: String = "957B88B12730E646E0F33D3618B77DFA579E8231E3C59C7104BE7165611C8027",
|
||||
name: String = "Test Account",
|
||||
name: String? = "Test Account",
|
||||
icon: String = "Letter",
|
||||
iconColor: String = "Azure",
|
||||
derivationIndex: Int = 0,
|
||||
|
|
@ -126,7 +132,7 @@ class ArchivedAccountConverterTest {
|
|||
private fun createDomain(): ArchivedAccount {
|
||||
return ArchivedAccount(
|
||||
accountId = AccountId.forCryptoPortfolio(userWalletId, DerivationIndex(0).getOrNull()!!),
|
||||
name = "Test Account".toAccountName(),
|
||||
name = AccountName("Test Account").getOrNull()!!,
|
||||
derivationIndex = 0.toDerivationIndex(),
|
||||
icon = CryptoPortfolioIcon.ofCustomAccount(
|
||||
value = CryptoPortfolioIcon.Icon.Letter,
|
||||
|
|
|
|||
|
|
@ -75,6 +75,14 @@ class CryptoPortfolioConverterTest {
|
|||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, accountName = null),
|
||||
expected = Result.success(
|
||||
createCryptoPortfolio(userWalletId = userWallet.walletId).copy(
|
||||
accountName = AccountName.DefaultMain,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, accountName = ""),
|
||||
expected = Result.failure(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.datasource.api.tangemTech.models.account.SaveWalletAccountsRes
|
|||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import io.mockk.every
|
||||
|
|
@ -37,7 +38,7 @@ class SaveWalletAccountsResponseConverterTest {
|
|||
accounts = listOf(
|
||||
WalletAccountDTO(
|
||||
id = accountList.mainAccount.accountId.value,
|
||||
name = accountList.mainAccount.accountName.value,
|
||||
name = (accountList.mainAccount.accountName as? AccountName.Custom)?.value,
|
||||
derivationIndex = accountList.mainAccount.derivationIndex.value,
|
||||
icon = accountList.mainAccount.icon.value.name,
|
||||
iconColor = accountList.mainAccount.icon.color.name,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import arrow.core.raise.ensure
|
|||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
|
|
@ -119,8 +120,8 @@ data class AccountList private constructor(
|
|||
}
|
||||
|
||||
@Serializable
|
||||
data object DuplicateAccountNames : Error {
|
||||
override fun toString(): String = "$tag: Account list contains duplicate account names"
|
||||
data class DuplicateAccountNames(val message: String) : Error {
|
||||
override fun toString(): String = "$tag: Account list contains duplicate account names. $message"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,8 +161,18 @@ data class AccountList private constructor(
|
|||
val uniqueAccountIdsCount = accounts.map { it.accountId.value }.distinct().size
|
||||
ensure(accounts.size == uniqueAccountIdsCount) { Error.DuplicateAccountIds }
|
||||
|
||||
val uniqueAccountNameCount = accounts.map { it.accountName.value }.distinct().size
|
||||
ensure(accounts.size == uniqueAccountNameCount) { Error.DuplicateAccountNames }
|
||||
val defaultMainNameCount = accounts.count { it.accountName is AccountName.DefaultMain }
|
||||
|
||||
val customNames = accounts.mapNotNull { (it.accountName as? AccountName.Custom)?.value }
|
||||
val uniqueCustomNameCount = customNames.distinct().size
|
||||
|
||||
ensure(defaultMainNameCount == 0 || defaultMainNameCount == 1) {
|
||||
Error.DuplicateAccountNames("Only one account can have the default main name.")
|
||||
}
|
||||
|
||||
ensure(customNames.size == uniqueCustomNameCount) {
|
||||
Error.DuplicateAccountNames("Custom account names must be unique.")
|
||||
}
|
||||
|
||||
AccountList(
|
||||
userWallet = userWallet,
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ class AccountListTest {
|
|||
createAccount(userWalletId = userWalletId, name = "Name", derivationIndex = 0),
|
||||
createAccount(userWalletId = userWalletId, name = "Name", derivationIndex = 1),
|
||||
),
|
||||
expected = AccountList.Error.DuplicateAccountNames.left(),
|
||||
expected = AccountList.Error.DuplicateAccountNames("Custom account names must be unique.").left(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ sealed interface Account {
|
|||
userWalletId = userWalletId,
|
||||
derivationIndex = derivationIndex,
|
||||
),
|
||||
accountName = AccountName.Main,
|
||||
accountName = AccountName.DefaultMain,
|
||||
icon = CryptoPortfolioIcon.ofMainAccount(userWalletId),
|
||||
derivationIndex = derivationIndex,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
|
|
|
|||
|
|
@ -8,14 +8,44 @@ import kotlinx.serialization.Serializable
|
|||
/**
|
||||
* Represents an account name
|
||||
*
|
||||
* @property value the validated account name as a string
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Serializable
|
||||
data class AccountName private constructor(
|
||||
val value: String,
|
||||
) {
|
||||
sealed interface AccountName {
|
||||
|
||||
/**
|
||||
* Represents the default main account name.
|
||||
* If the user renames the main account, it will be converted to a [Custom] account name.
|
||||
*/
|
||||
@Serializable
|
||||
data object DefaultMain : AccountName
|
||||
|
||||
/**
|
||||
* Represents a custom account name provided by the user
|
||||
*
|
||||
* @property value the string value of the custom account name
|
||||
*/
|
||||
@Serializable
|
||||
data class Custom private constructor(val value: String) : AccountName {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Factory method to create an [AccountName.Custom] instance.
|
||||
* Validates the input string to ensure it is not blank and does not exceed the maximum length.
|
||||
*
|
||||
* @param value the input string representing the account name
|
||||
*/
|
||||
operator fun invoke(value: String): Either<Error, Custom> = either {
|
||||
val trimmedValue = value.trim()
|
||||
|
||||
ensure(trimmedValue.isNotBlank()) { Error.Empty }
|
||||
ensure(trimmedValue.length <= MAX_LENGTH) { Error.ExceedsMaxLength }
|
||||
|
||||
Custom(value = trimmedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents possible validation errors
|
||||
|
|
@ -44,26 +74,14 @@ data class AccountName private constructor(
|
|||
|
||||
companion object {
|
||||
|
||||
private const val MAIN_ACCOUNT_NAME = "Main Account"
|
||||
private const val MAX_LENGTH = 20
|
||||
|
||||
/** Default name for the main account */
|
||||
val Main: AccountName
|
||||
get() = AccountName(value = MAIN_ACCOUNT_NAME)
|
||||
|
||||
/**
|
||||
* Factory method to create an `AccountName` instance.
|
||||
* Factory method to create an [AccountName] instance.
|
||||
* Validates the input string to ensure it is not blank and does not exceed the maximum length.
|
||||
*
|
||||
* @param value the input string representing the account name
|
||||
*/
|
||||
operator fun invoke(value: String): Either<Error, AccountName> = either {
|
||||
val trimmedValue = value.trim()
|
||||
|
||||
ensure(trimmedValue.isNotBlank()) { Error.Empty }
|
||||
ensure(trimmedValue.length <= MAX_LENGTH) { Error.ExceedsMaxLength }
|
||||
|
||||
AccountName(value = trimmedValue)
|
||||
}
|
||||
operator fun invoke(value: String): Either<Error, AccountName> = Custom(value)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package com.tangem.domain.models.account
|
|||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
|
|
@ -14,16 +13,6 @@ import org.junit.jupiter.params.provider.MethodSource
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class AccountNameTest {
|
||||
|
||||
@Test
|
||||
fun main_returnsMainAccountName() {
|
||||
// Act
|
||||
val main = AccountName.Main.value
|
||||
|
||||
// Assert
|
||||
val expected = "Main Account"
|
||||
Truth.assertThat(main).isEqualTo(expected)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideTestModels")
|
||||
fun invoke(model: InvokeTestModel) {
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ class AccountTest {
|
|||
userWalletId = userWalletId,
|
||||
derivationIndex = derivationIndex,
|
||||
),
|
||||
accountName = AccountName.Main,
|
||||
accountName = AccountName.DefaultMain,
|
||||
icon = CryptoPortfolioIcon.ofMainAccount(userWalletId),
|
||||
derivationIndex = derivationIndex,
|
||||
cryptoCurrencies = emptySet(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.account.archived
|
||||
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
|
|
@ -50,7 +51,7 @@ internal class ArchivedAccountListModel @Inject constructor(
|
|||
title = resourceReference(R.string.account_archived_recover_dialog_title),
|
||||
message = resourceReference(
|
||||
id = R.string.account_archived_recover_dialog_description,
|
||||
formatArgs = wrappedList(account.accountName.value),
|
||||
formatArgs = wrappedList(account.accountName.toUM().value),
|
||||
),
|
||||
firstActionBuilder = { firstAction },
|
||||
secondActionBuilder = { secondAction },
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.features.account.createedit
|
||||
|
||||
import com.tangem.common.ui.account.AccountNameUM
|
||||
import com.tangem.common.ui.account.toDomain
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -16,7 +18,6 @@ import com.tangem.core.ui.utils.showErrorDialog
|
|||
import com.tangem.domain.account.usecase.AddCryptoPortfolioUseCase
|
||||
import com.tangem.domain.account.usecase.GetUnoccupiedAccountIndexUseCase
|
||||
import com.tangem.domain.account.usecase.UpdateCryptoPortfolioUseCase
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
@ -92,7 +93,7 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
|
||||
private suspend fun createNewCryptoPortfolio(params: AccountCreateEditComponent.Params.Create) {
|
||||
val state = uiState.value
|
||||
val name = AccountName(value = state.account.name).getOrNull() ?: return
|
||||
val name = state.account.name.toDomain().getOrNull() ?: return
|
||||
val icon = state.account.portfolioIcon.toDomain()
|
||||
val index = state.account.derivationInfo.index ?: return
|
||||
val derivationIndex = DerivationIndex(value = index).getOrNull() ?: return
|
||||
|
|
@ -107,7 +108,7 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
|
||||
private suspend fun editCryptoPortfolio(params: AccountCreateEditComponent.Params.Edit) {
|
||||
val state = uiState.value
|
||||
val name = AccountName(state.account.name).getOrNull() ?: return
|
||||
val name = state.account.name.toDomain().getOrNull() ?: return
|
||||
val icon = state.account.portfolioIcon.toDomain()
|
||||
val isNewName = name != params.account.accountName
|
||||
val isNewIcon = icon != params.account.portfolioIcon
|
||||
|
|
@ -132,18 +133,20 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
.validateNewState()
|
||||
}
|
||||
|
||||
private fun onNameChange(name: String) {
|
||||
private fun onNameChange(name: AccountNameUM) {
|
||||
uiState.value = uiState.value
|
||||
.updateName(name)
|
||||
.validateNewState()
|
||||
}
|
||||
|
||||
private fun AccountCreateEditUM.validateNewState(): AccountCreateEditUM {
|
||||
val isValidName = AccountName(this.account.name).isRight()
|
||||
val isValidName = this.account.name.toDomain().isRight()
|
||||
val isAvailableForConfirm = when (params) {
|
||||
is AccountCreateEditComponent.Params.Create -> isValidName
|
||||
is AccountCreateEditComponent.Params.Edit -> {
|
||||
val isNewName = this.account.name != params.account.accountName.value
|
||||
val oldName = params.account.accountName.toUM()
|
||||
|
||||
val isNewName = this.account.name != oldName
|
||||
val isNewIcon = this.account.portfolioIcon != params.account.portfolioIcon
|
||||
isValidName && (isNewName || isNewIcon)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.account.createedit.entity
|
||||
|
||||
import com.tangem.common.ui.account.AccountNameUM
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
|
|
@ -15,11 +16,11 @@ internal data class AccountCreateEditUM(
|
|||
) {
|
||||
|
||||
data class Account(
|
||||
val name: String,
|
||||
val name: AccountNameUM,
|
||||
val portfolioIcon: CryptoPortfolioIconUM,
|
||||
val derivationInfo: DerivationInfo,
|
||||
val inputPlaceholder: TextReference,
|
||||
val onNameChange: (String) -> Unit,
|
||||
val onNameChange: (AccountNameUM) -> Unit,
|
||||
)
|
||||
|
||||
sealed interface DerivationInfo {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.account.createedit.entity
|
||||
|
||||
import com.tangem.common.ui.account.AccountNameUM
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.res.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -24,17 +25,17 @@ internal class AccountCreateEditUMBuilder(
|
|||
is AccountCreateEditComponent.Params.Edit -> resourceReference(R.string.account_form_title_edit)
|
||||
}
|
||||
|
||||
fun initAccountUM(onNameChange: (String) -> Unit): AccountCreateEditUM.Account {
|
||||
fun initAccountUM(onNameChange: (AccountNameUM) -> Unit): AccountCreateEditUM.Account {
|
||||
return when (params) {
|
||||
is AccountCreateEditComponent.Params.Create -> AccountCreateEditUM.Account(
|
||||
name = "",
|
||||
name = AccountNameUM.Custom(raw = ""),
|
||||
portfolioIcon = createIcon,
|
||||
derivationInfo = AccountCreateEditUM.DerivationInfo.Empty,
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_new_account),
|
||||
onNameChange = onNameChange,
|
||||
)
|
||||
is AccountCreateEditComponent.Params.Edit -> AccountCreateEditUM.Account(
|
||||
name = params.account.accountName.value,
|
||||
name = params.account.accountName.toUM(),
|
||||
portfolioIcon = params.account.portfolioIcon.toUM(),
|
||||
derivationInfo = createAccountDerivationInfo(
|
||||
index = (params.account as Account.CryptoPortfolio).derivationIndex.value,
|
||||
|
|
@ -108,7 +109,7 @@ internal class AccountCreateEditUMBuilder(
|
|||
)
|
||||
}
|
||||
|
||||
fun AccountCreateEditUM.updateName(name: String): AccountCreateEditUM {
|
||||
fun AccountCreateEditUM.updateName(name: AccountNameUM): AccountCreateEditUM {
|
||||
return this.copy(account = this.account.copy(name = name))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -24,11 +25,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.account.AccountIcon
|
||||
import com.tangem.common.ui.account.AccountIconPreviewData
|
||||
import com.tangem.common.ui.account.AccountIconSize
|
||||
import com.tangem.common.ui.account.getResId
|
||||
import com.tangem.common.ui.account.getUiColor
|
||||
import com.tangem.common.ui.account.*
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
|
|
@ -43,7 +40,6 @@ import com.tangem.features.account.createedit.entity.AccountCreateEditUM
|
|||
import com.tangem.features.account.createedit.entity.AccountCreateEditUM.Account
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Suppress("LongMethod", "MagicNumber")
|
||||
@Composable
|
||||
internal fun AccountCreateEditContent(state: AccountCreateEditUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
|
|
@ -65,7 +61,6 @@ internal fun AccountCreateEditContent(state: AccountCreateEditUM, modifier: Modi
|
|||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.weight(1f),
|
||||
|
||||
) {
|
||||
AccountSummary(state.account)
|
||||
SpacerH24()
|
||||
|
|
@ -103,7 +98,7 @@ private fun AccountSummary(account: Account) {
|
|||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
AccountIcon(
|
||||
name = stringReference(account.name),
|
||||
name = account.name.value,
|
||||
icon = account.portfolioIcon,
|
||||
size = AccountIconSize.Large,
|
||||
)
|
||||
|
|
@ -116,13 +111,27 @@ private fun AccountSummary(account: Account) {
|
|||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
val wasDefault = remember { account.name is AccountNameUM.DefaultMain }
|
||||
val defaultAccountName = AccountNameUM.DefaultMain.value.resolveReference()
|
||||
AutoSizeTextField(
|
||||
centered = true,
|
||||
textStyle = TangemTheme.typography.head,
|
||||
placeholder = account.inputPlaceholder,
|
||||
value = account.name,
|
||||
value = account.name.value.resolveReference(),
|
||||
singleLine = true,
|
||||
onValueChange = account.onNameChange,
|
||||
onValueChange = {
|
||||
/*
|
||||
* If the user had the default main account name and enters the same name during renaming,
|
||||
* we should use the default value instead of custom to avoid breaking the name validation process.
|
||||
*/
|
||||
val newName = if (wasDefault && it == defaultAccountName) {
|
||||
AccountNameUM.DefaultMain
|
||||
} else {
|
||||
AccountNameUM.Custom(raw = it)
|
||||
}
|
||||
|
||||
account.onNameChange(newName)
|
||||
},
|
||||
)
|
||||
SpacerH(20.dp)
|
||||
}
|
||||
|
|
@ -279,7 +288,7 @@ private class PreviewStateProvider : CollectionPreviewParameterProvider<AccountC
|
|||
title = stringReference("Add account"),
|
||||
onCloseClick = {},
|
||||
account = Account(
|
||||
name = "",
|
||||
name = AccountNameUM.DefaultMain,
|
||||
portfolioIcon = portfolioIcon,
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_new_account),
|
||||
onNameChange = {},
|
||||
|
|
@ -313,7 +322,7 @@ private class PreviewStateProvider : CollectionPreviewParameterProvider<AccountC
|
|||
onCloseClick = {},
|
||||
account = Account(
|
||||
portfolioIcon = portfolioIcon,
|
||||
name = accountName,
|
||||
name = AccountNameUM.Custom(raw = accountName),
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_edit_account),
|
||||
onNameChange = {},
|
||||
derivationInfo = AccountCreateEditUM.DerivationInfo.Content(
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ internal class AccountDetailsModel @Inject constructor(
|
|||
|
||||
private fun getInitialState(): AccountDetailsUM {
|
||||
return AccountDetailsUM(
|
||||
accountName = params.account.accountName.value,
|
||||
accountName = params.account.accountName.toUM().value,
|
||||
accountIcon = params.account.portfolioIcon.toUM(),
|
||||
onCloseClick = { router.pop() },
|
||||
onAccountEditClick = ::onEditAccountClick,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
package com.tangem.features.account.details.entity
|
||||
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class AccountDetailsUM(
|
||||
val accountName: String,
|
||||
val accountName: TextReference,
|
||||
val accountIcon: CryptoPortfolioIconUM,
|
||||
val onCloseClick: () -> Unit,
|
||||
val onAccountEditClick: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ private fun AccountRow(state: AccountDetailsUM) {
|
|||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
AccountRow(
|
||||
title = stringReference(state.accountName),
|
||||
title = state.accountName,
|
||||
subtitle = resourceReference(R.string.account_form_name),
|
||||
icon = state.accountIcon,
|
||||
modifier = Modifier.weight(1f),
|
||||
|
|
@ -177,7 +177,7 @@ private class PreviewStateProvider : CollectionPreviewParameterProvider<AccountD
|
|||
onAccountEditClick = {},
|
||||
onManageTokensClick = {},
|
||||
onArchiveAccountClick = {},
|
||||
accountName = accountName,
|
||||
accountName = stringReference(value = accountName),
|
||||
accountIcon = portfolioIcon,
|
||||
)
|
||||
add(first)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.tangem.core.decompose.ui.UiMessageSender
|
|||
import com.tangem.core.ui.components.block.model.BlockUM
|
||||
import com.tangem.core.ui.extensions.pluralReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
|
|
@ -59,7 +58,7 @@ internal class AccountItemsDelegate @Inject constructor(
|
|||
private fun Account.CryptoPortfolio.mapCryptoPortfolio(): WalletSettingsAccountsUM {
|
||||
return WalletSettingsAccountsUM.Account(
|
||||
id = accountId.value,
|
||||
accountName = stringReference(accountName.value),
|
||||
accountName = accountName.toUM().value,
|
||||
accountIconUM = icon.toUM(),
|
||||
tokensInfo = pluralReference(
|
||||
R.plurals.common_tokens_count,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue