Updated on 2026-08-14
This commit is contained in:
parent
cf6b5dbabb
commit
853304539d
12 changed files with 285 additions and 28 deletions
|
|
@ -20,6 +20,7 @@ dependencies {
|
|||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.error)
|
||||
implementation(projects.core.res)
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.navigation)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.features.account.createedit
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -9,11 +11,14 @@ import com.tangem.core.res.R
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
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
|
||||
import com.tangem.features.account.AccountCreateEditComponent
|
||||
import com.tangem.features.account.common.toDomain
|
||||
import com.tangem.features.account.createedit.entity.AccountCreateEditUM
|
||||
|
|
@ -21,15 +26,20 @@ import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder
|
|||
import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder.Companion.portfolioIcon
|
||||
import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder.Companion.updateButton
|
||||
import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder.Companion.updateColorSelect
|
||||
import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder.Companion.updateDerivationIndex
|
||||
import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder.Companion.updateIconSelect
|
||||
import com.tangem.features.account.createedit.entity.AccountCreateEditUMBuilder.Companion.updateName
|
||||
import com.tangem.features.account.createedit.error.AccountFeatureError
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class AccountCreateEditModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val messageSender: UiMessageSender,
|
||||
|
|
@ -37,13 +47,21 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val updateCryptoPortfolioUseCase: UpdateCryptoPortfolioUseCase,
|
||||
private val addCryptoPortfolioUseCase: AddCryptoPortfolioUseCase,
|
||||
private val getUnoccupiedAccountIndexUseCase: GetUnoccupiedAccountIndexUseCase,
|
||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<AccountCreateEditComponent.Params>()
|
||||
private val umBuilder = AccountCreateEditUMBuilder(params)
|
||||
|
||||
val uiState: StateFlow<AccountCreateEditUM> get() = _uiState
|
||||
private val _uiState = MutableStateFlow(value = getInitialState())
|
||||
val uiState: StateFlow<AccountCreateEditUM>
|
||||
field = MutableStateFlow(value = getInitialState())
|
||||
|
||||
init {
|
||||
if (params is AccountCreateEditComponent.Params.Create) {
|
||||
updateDerivationInfo(userWalletId = params.userWalletId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsaveChangeDialog() {
|
||||
val secondAction = EventMessageAction(
|
||||
|
|
@ -74,13 +92,16 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
|
||||
private suspend fun createNewCryptoPortfolio(params: AccountCreateEditComponent.Params.Create) {
|
||||
val state = uiState.value
|
||||
val name = AccountName(state.account.name).getOrNull() ?: return
|
||||
val name = AccountName(value = state.account.name).getOrNull() ?: return
|
||||
val icon = state.account.portfolioIcon.toDomain()
|
||||
val index = state.account.derivationInfo.index ?: return
|
||||
val derivationIndex = DerivationIndex(value = index).getOrNull() ?: return
|
||||
|
||||
addCryptoPortfolioUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
accountName = name,
|
||||
icon = icon,
|
||||
derivationIndex = DerivationIndex.Main, // todo account
|
||||
derivationIndex = derivationIndex,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -100,19 +121,19 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
private fun onCloseClick() = unsaveChangeDialog()
|
||||
|
||||
private fun onIconSelect(icon: CryptoPortfolioIcon.Icon) {
|
||||
_uiState.value = uiState.value
|
||||
uiState.value = uiState.value
|
||||
.updateIconSelect(icon)
|
||||
.validateNewState()
|
||||
}
|
||||
|
||||
private fun onColorSelect(color: CryptoPortfolioIcon.Color) {
|
||||
_uiState.value = uiState.value
|
||||
uiState.value = uiState.value
|
||||
.updateColorSelect(color)
|
||||
.validateNewState()
|
||||
}
|
||||
|
||||
private fun onNameChange(name: String) {
|
||||
_uiState.value = uiState.value
|
||||
uiState.value = uiState.value
|
||||
.updateName(name)
|
||||
.validateNewState()
|
||||
}
|
||||
|
|
@ -140,4 +161,35 @@ internal class AccountCreateEditModel @Inject constructor(
|
|||
onCloseClick = ::onCloseClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateDerivationInfo(userWalletId: UserWalletId) {
|
||||
modelScope.launch(dispatchers.default) {
|
||||
getUnoccupiedAccountIndexUseCase(userWalletId = userWalletId)
|
||||
.onRight { derivationIndex ->
|
||||
uiState.update {
|
||||
it.updateDerivationIndex(derivationIndex = derivationIndex.value)
|
||||
}
|
||||
}
|
||||
.onLeft {
|
||||
handleError(
|
||||
error = AccountFeatureError.CreateAccount.UnableToGetDerivationIndex,
|
||||
params = mapOf("userWalletId" to userWalletId.stringValue),
|
||||
)
|
||||
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleError(error: AccountFeatureError, params: Map<String, String> = mapOf()) {
|
||||
val exception = IllegalStateException(error.toString())
|
||||
|
||||
Timber.e(exception)
|
||||
|
||||
analyticsExceptionHandler.sendException(
|
||||
event = ExceptionAnalyticsEvent(exception = exception, params = params),
|
||||
)
|
||||
|
||||
messageSender.showErrorDialog(universalError = error, onDismiss = router::pop)
|
||||
}
|
||||
}
|
||||
|
|
@ -17,11 +17,23 @@ data class AccountCreateEditUM(
|
|||
data class Account(
|
||||
val name: String,
|
||||
val portfolioIcon: CryptoPortfolioIconUM,
|
||||
val derivationInfo: TextReference,
|
||||
val derivationInfo: DerivationInfo,
|
||||
val inputPlaceholder: TextReference,
|
||||
val onNameChange: (String) -> Unit,
|
||||
)
|
||||
|
||||
sealed interface DerivationInfo {
|
||||
val text: TextReference
|
||||
val index: Int?
|
||||
|
||||
data class Content(override val text: TextReference, override val index: Int) : DerivationInfo
|
||||
|
||||
data object Empty : DerivationInfo {
|
||||
override val text: TextReference = TextReference.EMPTY
|
||||
override val index: Int? = null
|
||||
}
|
||||
}
|
||||
|
||||
data class Colors(
|
||||
val selected: CryptoPortfolioIcon.Color,
|
||||
val list: ImmutableList<CryptoPortfolioIcon.Color>,
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@ package com.tangem.features.account.createedit.entity
|
|||
import com.tangem.core.res.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.features.account.AccountCreateEditComponent
|
||||
import com.tangem.features.account.common.toUM
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AccountCreateEditUMBuilder @Inject constructor(
|
||||
val params: AccountCreateEditComponent.Params,
|
||||
internal class AccountCreateEditUMBuilder(
|
||||
private val params: AccountCreateEditComponent.Params,
|
||||
) {
|
||||
|
||||
private val accountColors = CryptoPortfolioIcon.Color.entries.toImmutableList()
|
||||
|
|
@ -29,14 +29,16 @@ internal class AccountCreateEditUMBuilder @Inject constructor(
|
|||
is AccountCreateEditComponent.Params.Create -> AccountCreateEditUM.Account(
|
||||
name = "",
|
||||
portfolioIcon = createIcon,
|
||||
derivationInfo = TextReference.EMPTY,
|
||||
derivationInfo = AccountCreateEditUM.DerivationInfo.Empty,
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_new_account),
|
||||
onNameChange = onNameChange,
|
||||
)
|
||||
is AccountCreateEditComponent.Params.Edit -> AccountCreateEditUM.Account(
|
||||
name = params.account.name.value,
|
||||
portfolioIcon = params.account.portfolioIcon.toUM(),
|
||||
derivationInfo = TextReference.EMPTY, // todo account use Account.CryptoPortfolio.derivationIndex ?
|
||||
derivationInfo = createAccountDerivationInfo(
|
||||
index = (params.account as Account.CryptoPortfolio).derivationIndex.value,
|
||||
),
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_edit_account),
|
||||
onNameChange = onNameChange,
|
||||
)
|
||||
|
|
@ -113,5 +115,25 @@ internal class AccountCreateEditUMBuilder @Inject constructor(
|
|||
fun AccountCreateEditUM.updateButton(isButtonEnabled: Boolean): AccountCreateEditUM {
|
||||
return this.copy(buttonState = this.buttonState.copy(isButtonEnabled = isButtonEnabled))
|
||||
}
|
||||
|
||||
fun AccountCreateEditUM.updateDerivationIndex(derivationIndex: Int): AccountCreateEditUM {
|
||||
return this.copy(
|
||||
account = this.account.copy(
|
||||
derivationInfo = createAccountDerivationInfo(index = derivationIndex),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createAccountDerivationInfo(index: Int): AccountCreateEditUM.DerivationInfo {
|
||||
val derivationIndexText = if (index.toString().length == 1) "0$index" else "$index"
|
||||
|
||||
return AccountCreateEditUM.DerivationInfo.Content(
|
||||
text = resourceReference(
|
||||
id = R.string.account_form_account_index,
|
||||
formatArgs = wrappedList(derivationIndexText),
|
||||
),
|
||||
index = index,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.features.account.createedit.error
|
||||
|
||||
import com.tangem.core.error.UniversalError
|
||||
|
||||
sealed interface AccountFeatureError : UniversalError {
|
||||
|
||||
val subsystemCode: String
|
||||
val specificErrorCode: String
|
||||
|
||||
override val errorCode: Int
|
||||
get() = "108$subsystemCode$specificErrorCode".toInt()
|
||||
|
||||
sealed interface CreateAccount : AccountFeatureError {
|
||||
|
||||
override val subsystemCode: String get() = "001"
|
||||
|
||||
data object UnableToGetDerivationIndex : CreateAccount {
|
||||
override val specificErrorCode: String = "001"
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface EditAccount : AccountFeatureError {
|
||||
|
||||
override val subsystemCode: String get() = "002"
|
||||
|
||||
data object RequiredCryptoPortfolio : EditAccount {
|
||||
override val specificErrorCode: String = "001"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,10 +32,7 @@ import com.tangem.core.ui.components.SpacerH24
|
|||
import com.tangem.core.ui.components.SpacerH8
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.components.fields.AutoSizeTextField
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
|
|
@ -76,7 +73,7 @@ internal fun AccountCreateEditContent(state: AccountCreateEditUM, modifier: Modi
|
|||
SpacerH8()
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
text = state.account.derivationInfo.resolveReference(),
|
||||
text = state.account.derivationInfo.text.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
@ -93,7 +90,7 @@ internal fun AccountCreateEditContent(state: AccountCreateEditUM, modifier: Modi
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AccountSummary(account: AccountCreateEditUM.Account) {
|
||||
private fun AccountSummary(account: Account) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
|
|
@ -126,7 +123,7 @@ private fun AccountSummary(account: AccountCreateEditUM.Account) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AccountIcon(account: AccountCreateEditUM.Account) {
|
||||
private fun AccountIcon(account: Account) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
|
|
@ -308,7 +305,10 @@ private class PreviewStateProvider : CollectionPreviewParameterProvider<AccountC
|
|||
portfolioIcon = portfolioIcon,
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_new_account),
|
||||
onNameChange = {},
|
||||
derivationInfo = stringReference("Account #03 — used for address derivation."),
|
||||
derivationInfo = AccountCreateEditUM.DerivationInfo.Content(
|
||||
text = resourceReference(id = R.string.account_form_account_index, formatArgs = wrappedList(1)),
|
||||
index = 1,
|
||||
),
|
||||
),
|
||||
colorsState = AccountCreateEditUM.Colors(
|
||||
selected = portfolioIcon.color,
|
||||
|
|
@ -340,7 +340,10 @@ private class PreviewStateProvider : CollectionPreviewParameterProvider<AccountC
|
|||
name = "Main account",
|
||||
inputPlaceholder = resourceReference(R.string.account_form_placeholder_edit_account),
|
||||
onNameChange = {},
|
||||
derivationInfo = stringReference("Account #03 — used for address derivation."),
|
||||
derivationInfo = AccountCreateEditUM.DerivationInfo.Content(
|
||||
text = resourceReference(id = R.string.account_form_account_index, formatArgs = wrappedList(1)),
|
||||
index = 1,
|
||||
),
|
||||
),
|
||||
colorsState = AccountCreateEditUM.Colors(
|
||||
selected = portfolioIcon.color,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue