Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-23 17:02:30 +04:00
commit 11bd3bc722
8 changed files with 70 additions and 10 deletions

View file

@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.update
internal class PreviewManageTokensComponent(
private val isLoading: Boolean,
private val showTangemIcon: Boolean,
params: ManageTokensComponent.Params,
) : ManageTokensComponent {
@ -65,6 +66,7 @@ internal class PreviewManageTokensComponent(
loadMore = { false },
saveChanges = {},
isSavingInProgress = false,
needToAddDerivations = showTangemIcon,
),
)

View file

@ -14,6 +14,7 @@ internal data class CustomTokenFormUM(
val notifications: PersistentList<NotificationUM> = persistentListOf(),
val canAddToken: Boolean = false,
val isValidating: Boolean = false,
val needToAddDerivation: Boolean = false,
val saveToken: () -> Unit,
) {

View file

@ -42,6 +42,7 @@ internal sealed class ManageTokensUM {
val saveChanges: () -> Unit,
val hasChanges: Boolean,
val isSavingInProgress: Boolean,
val needToAddDerivations: Boolean,
) : ManageTokensUM()
fun copySealed(
@ -52,6 +53,7 @@ internal sealed class ManageTokensUM {
isNextBatchLoading: Boolean = this.isNextBatchLoading,
isSavingInProgress: Boolean = this is ManageContent && this.isSavingInProgress,
scrollToTop: StateEvent<Unit> = this.scrollToTop,
needToAddDerivations: Boolean = this is ManageContent && this.needToAddDerivations,
): ManageTokensUM {
return when (this) {
is ManageContent -> copy(
@ -62,6 +64,7 @@ internal sealed class ManageTokensUM {
isNextBatchLoading = isNextBatchLoading,
isSavingInProgress = isSavingInProgress,
scrollToTop = scrollToTop,
needToAddDerivations = needToAddDerivations,
)
is ReadContent -> copy(
search = search,

View file

@ -12,6 +12,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.message.ContentMessage
import com.tangem.domain.card.DerivePublicKeysUseCase
import com.tangem.domain.card.HasMissedDerivationsUseCase
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
@ -43,6 +44,7 @@ internal class CustomTokenFormModel @Inject constructor(
private val customCurrencyValidator: CustomCurrencyValidator,
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase,
private val messageSender: UiMessageSender,
private val customTokenFormManager: CustomCurrencyFormBuilder,
private val analyticsEventHandler: AnalyticsEventHandler,
@ -156,7 +158,12 @@ internal class CustomTokenFormModel @Inject constructor(
fillForm: Boolean,
isAlreadyAdded: Boolean,
isCustom: Boolean,
) {
) = modelScope.launch {
val needToAddDerivation = hasMissedDerivationsUseCase(
userWalletId = params.userWalletId,
networksWithDerivationPath = mapOf(currency.network.backendId to getDerivationPath().value),
)
state.update { state ->
var updatedState = state
.updateWithProgress(
@ -166,6 +173,7 @@ internal class CustomTokenFormModel @Inject constructor(
clearNotifications = true,
clearFieldErrors = true,
disableSecondaryFields = !isCustom,
needToAddDerivation = needToAddDerivation,
)
if (fillForm) {

View file

@ -17,6 +17,7 @@ import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.card.HasMissedDerivationsUseCase
import com.tangem.domain.managetokens.SaveManagedTokensUseCase
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
@ -47,6 +48,7 @@ internal class ManageTokensModel @Inject constructor(
private val router: Router,
private val manageTokensListManager: ManageTokensListManager,
private val messageSender: UiMessageSender,
private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase,
private val saveManagedTokensUseCase: SaveManagedTokensUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
paramsContainer: ParamsContainer,
@ -140,6 +142,7 @@ internal class ManageTokensModel @Inject constructor(
hasChanges = false,
saveChanges = ::saveChanges,
loadMore = ::loadMoreItems,
needToAddDerivations = false,
isSavingInProgress = false,
)
}
@ -255,10 +258,22 @@ internal class ManageTokensModel @Inject constructor(
}
private fun updateChangedItems(currenciesToAdd: ChangedCurrencies, currenciesToRemove: ChangedCurrencies) {
state.update { state ->
state.copySealed(
hasChanges = currenciesToAdd.isNotEmpty() || currenciesToRemove.isNotEmpty(),
)
modelScope.launch {
val hasMissedDerivations = params.userWalletId?.let { walletId ->
val networks = currenciesToAdd.values
.flatten()
.toSet()
.associate { it.backendId to null }
hasMissedDerivationsUseCase(walletId, networks)
}
state.update { state ->
state.copySealed(
hasChanges = currenciesToAdd.isNotEmpty() || currenciesToRemove.isNotEmpty(),
needToAddDerivations = hasMissedDerivations ?: false,
)
}
}
}

View file

@ -22,9 +22,11 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.block.information.InformationBlock
import com.tangem.core.ui.components.bottomFade
import com.tangem.core.ui.components.buttons.common.TangemButton
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
import com.tangem.core.ui.components.fields.SimpleTextField
import com.tangem.core.ui.components.isOpened
import com.tangem.core.ui.components.keyboardAsState
@ -82,14 +84,22 @@ internal fun CustomTokenFormContent(model: CustomTokenFormUM, modifier: Modifier
}
}
PrimaryButton(
TangemButton(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = TangemTheme.dimens.spacing16 + bottomBarHeight)
.fillMaxWidth(),
text = stringResource(id = R.string.custom_token_add_token),
colors = TangemButtonsDefaults.primaryButtonColors,
enabled = model.canAddToken,
showProgress = model.isValidating,
animateContentChange = true,
icon = if (model.needToAddDerivation) {
TangemButtonIconPosition.End(R.drawable.ic_tangem_24)
} else {
TangemButtonIconPosition.None
},
textStyle = TangemTheme.typography.subtitle1,
onClick = model.saveToken,
)
}

View file

@ -33,11 +33,17 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.BottomFade
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.TangemSwitch
import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.buttons.SecondarySmallButton
import com.tangem.core.ui.components.buttons.SmallButtonConfig
import com.tangem.core.ui.components.buttons.common.TangemButton
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.fields.SearchBar
@ -122,6 +128,7 @@ internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modi
.fillMaxWidth(),
isVisible = state.hasChanges,
showProgress = state.isSavingInProgress,
showIcon = state.needToAddDerivations,
onClick = state.saveChanges,
)
}
@ -158,6 +165,7 @@ private fun ManageTokensTopBar(topBar: ManageTokensTopBarUM?, search: SearchBarU
private fun SaveChangesButton(
isVisible: Boolean,
showProgress: Boolean,
showIcon: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -168,10 +176,18 @@ private fun SaveChangesButton(
exit = fadeOut(),
label = "save_button_visibility",
) {
PrimaryButtonIconEnd(
TangemButton(
text = stringResource(id = R.string.common_save),
iconResId = R.drawable.ic_tangem_24,
icon = if (showIcon) {
TangemButtonIconPosition.End(R.drawable.ic_tangem_24)
} else {
TangemButtonIconPosition.None
},
showProgress = showProgress,
colors = TangemButtonsDefaults.primaryButtonColors,
textStyle = TangemTheme.typography.subtitle1,
enabled = true,
animateContentChange = true,
onClick = onClick,
)
}
@ -472,6 +488,7 @@ private class PreviewManageTokensComponentProvider : PreviewParameterProvider<Ma
get() = sequenceOf(
PreviewManageTokensComponent(
isLoading = true,
showTangemIcon = true,
params = ManageTokensComponent.Params(
source = ManageTokensSource.ONBOARDING,
userWalletId = UserWalletId("wallet_id"),
@ -479,10 +496,12 @@ private class PreviewManageTokensComponentProvider : PreviewParameterProvider<Ma
),
PreviewManageTokensComponent(
isLoading = false,
showTangemIcon = true,
params = ManageTokensComponent.Params(source = ManageTokensSource.ONBOARDING, userWalletId = null),
),
PreviewManageTokensComponent(
isLoading = false,
showTangemIcon = false,
params = ManageTokensComponent.Params(
source = ManageTokensSource.ONBOARDING,
userWalletId = UserWalletId("wallet_id"),

View file

@ -27,6 +27,7 @@ internal fun CustomTokenFormUM.updateWithProgress(
showProgress: Boolean,
isWasFilled: Boolean = this.tokenForm?.wasFilled ?: false,
canAddToken: Boolean = this.canAddToken,
needToAddDerivation: Boolean = false,
clearNotifications: Boolean = false,
clearFieldErrors: Boolean = false,
disableSecondaryFields: Boolean = false,
@ -34,6 +35,7 @@ internal fun CustomTokenFormUM.updateWithProgress(
return copy(
isValidating = showProgress,
canAddToken = canAddToken,
needToAddDerivation = needToAddDerivation,
notifications = if (clearNotifications) persistentListOf() else notifications,
).updateTokenForm {
val updatedFields = fields.mapValues { (key, field) ->