Updated on 2026-08-14
This commit is contained in:
parent
aabfc1bba1
commit
422afbc17f
7 changed files with 934 additions and 44 deletions
|
|
@ -0,0 +1,60 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
|
||||
internal fun GetSelectedWalletSyncUseCase.unwrap(): UserWallet? {
|
||||
return this().fold(
|
||||
ifLeft = {
|
||||
Timber.e("Impossible to get selected wallet $it")
|
||||
null
|
||||
},
|
||||
ifRight = { it },
|
||||
)
|
||||
}
|
||||
|
||||
internal suspend fun GetPrimaryCurrencyStatusUpdatesUseCase.unwrap(userWalletId: UserWalletId): CryptoCurrencyStatus? {
|
||||
return this(userWalletId)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.filter(Either<CurrencyStatusError, CryptoCurrencyStatus>::isRight)
|
||||
.firstOrNull()
|
||||
?.fold(
|
||||
ifLeft = {
|
||||
Timber.e("Impossible to get primary currency status $it")
|
||||
null
|
||||
},
|
||||
ifRight = { it },
|
||||
)
|
||||
}
|
||||
|
||||
internal suspend fun GetSelectedAppCurrencyUseCase.unwrap(): AppCurrency {
|
||||
return this()
|
||||
.map { maybeAppCurrency ->
|
||||
maybeAppCurrency.getOrElse { AppCurrency.Default }
|
||||
}
|
||||
.firstOrNull()
|
||||
?: AppCurrency.Default
|
||||
}
|
||||
|
||||
internal suspend fun GetPrimaryCurrencyStatusUpdatesUseCase.collectLatest(
|
||||
userWalletId: UserWalletId,
|
||||
onRight: suspend (CryptoCurrencyStatus) -> Unit,
|
||||
) {
|
||||
this(userWalletId = userWalletId)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { maybeStatus ->
|
||||
maybeStatus.onRight { onRight(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* Base wallet click intents component.
|
||||
* Provides router and viewModelScope to child classes.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("UnnecessaryAbstractClass")
|
||||
internal abstract class BaseWalletClickIntents {
|
||||
|
||||
protected val router: InnerWalletRouter get() = _router
|
||||
protected val viewModelScope: CoroutineScope get() = _viewModelScope
|
||||
|
||||
private var _router: InnerWalletRouter by Delegates.notNull()
|
||||
private var _viewModelScope: CoroutineScope by Delegates.notNull()
|
||||
|
||||
open fun initialize(router: InnerWalletRouter, coroutineScope: CoroutineScope) {
|
||||
_router = router
|
||||
_viewModelScope = coroutineScope
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,20 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.UpdateWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal interface WalletCardClickIntents {
|
||||
|
||||
fun onRenameClick(userWalletId: UserWalletId, name: String)
|
||||
|
|
@ -15,17 +24,48 @@ internal interface WalletCardClickIntents {
|
|||
fun onDeleteAfterConfirmationClick(userWalletId: UserWalletId)
|
||||
}
|
||||
|
||||
internal class WalletCardClickIntentsImplementor @Inject constructor() : WalletCardClickIntents {
|
||||
internal class WalletCardClickIntentsImplementor @Inject constructor(
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val walletEventSender: WalletEventSender,
|
||||
// TODO: private val walletScreenContentLoader: WalletScreenContentLoader,
|
||||
private val updateWalletUseCase: UpdateWalletUseCase,
|
||||
private val deleteWalletUseCase: DeleteWalletUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : BaseWalletClickIntents(), WalletCardClickIntents {
|
||||
|
||||
override fun onRenameClick(userWalletId: UserWalletId, name: String) {
|
||||
// TODO
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
updateWalletUseCase(userWalletId = userWalletId, update = { it.copy(name) })
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDeleteBeforeConfirmationClick(userWalletId: UserWalletId) {
|
||||
// TODO
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.ShowAlert(
|
||||
state = WalletAlertState.RemoveWalletAlert(
|
||||
onConfirmClick = { onDeleteAfterConfirmationClick(userWalletId) },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDeleteAfterConfirmationClick(userWalletId: UserWalletId) {
|
||||
// TODO
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
// TODO: walletScreenContentLoader.cancel(userWalletId)
|
||||
deleteWalletUseCase(userWalletId)
|
||||
.onRight { popBackIfAllWalletsIsLocked() }
|
||||
.onLeft { Timber.e(it.toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun popBackIfAllWalletsIsLocked() {
|
||||
val wallets = stateHolder.value.wallets.map(WalletState::walletCardState)
|
||||
val unlockedWallet = wallets.count { it !is WalletCardState.LockedContent }
|
||||
|
||||
if (unlockedWallet == 1) {
|
||||
router.popBackStack(
|
||||
screen = if (wallets.size > 1) AppScreen.Welcome else AppScreen.Home,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,150 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.settings.NeverToShowWalletsScrollPreview
|
||||
import com.tangem.domain.tokens.FetchCardTokenListUseCase
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.FetchTokenListUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.SelectWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.PortfolioEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetRefreshStateTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTokenListErrorTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
internal class WalletClickIntentsV2 @Inject constructor(
|
||||
private val walletCardClickIntentsImplementor: WalletCardClickIntentsImplementor,
|
||||
private val warningsClickIntentsImplementer: WalletWarningsClickIntentsImplementer,
|
||||
private val currencyActionsClickIntentsImplementor: WalletCurrencyActionsClickIntentsImplementor,
|
||||
private val contentClickIntentsImplementor: WalletContentClickIntentsImplementor,
|
||||
) : WalletCardClickIntents by walletCardClickIntentsImplementor,
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
// TODO: private val walletScreenContentLoader: WalletScreenContentLoader,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val selectWalletUseCase: SelectWalletUseCase,
|
||||
// TODO: private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val fetchTokenListUseCase: FetchTokenListUseCase,
|
||||
private val fetchCardTokenListUseCase: FetchCardTokenListUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val neverToShowWalletsScrollPreview: NeverToShowWalletsScrollPreview,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : BaseWalletClickIntents(),
|
||||
WalletCardClickIntents by walletCardClickIntentsImplementor,
|
||||
WalletWarningsClickIntents by warningsClickIntentsImplementer,
|
||||
WalletCurrencyActionsClickIntents by currencyActionsClickIntentsImplementor,
|
||||
WalletContentClickIntents by contentClickIntentsImplementor {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
override fun initialize(router: InnerWalletRouter, coroutineScope: CoroutineScope) {
|
||||
super.initialize(router, coroutineScope)
|
||||
|
||||
walletCardClickIntentsImplementor.initialize(router, coroutineScope)
|
||||
warningsClickIntentsImplementer.initialize(router, coroutineScope)
|
||||
currencyActionsClickIntentsImplementor.initialize(router, coroutineScope)
|
||||
contentClickIntentsImplementor.initialize(router, coroutineScope)
|
||||
}
|
||||
|
||||
fun onWalletChange(index: Int) {
|
||||
// TODO
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
launch(dispatchers.main) { neverToShowWalletsScrollPreview() }
|
||||
|
||||
val maybeUserWallet = selectWalletUseCase(
|
||||
userWalletId = stateHolder.value.wallets[index].walletCardState.id,
|
||||
)
|
||||
|
||||
stateHolder.update { it.copy(selectedWalletIndex = index) }
|
||||
|
||||
maybeUserWallet.onRight {
|
||||
// TODO:
|
||||
// walletScreenContentLoader.load(
|
||||
// userWallet = it,
|
||||
// appCurrency = getSelectedAppCurrencyUseCase.unwrap(),
|
||||
// clickIntents = this@WalletClickIntentsV2,
|
||||
// coroutineScope = viewModelScope,
|
||||
// )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onRefreshSwipe() {
|
||||
// TODO
|
||||
when (stateHolder.getSelectedWallet()) {
|
||||
is WalletState.MultiCurrency.Content -> {
|
||||
analyticsEventHandler.send(PortfolioEvent.Refreshed)
|
||||
refreshMultiCurrencyContent()
|
||||
}
|
||||
is WalletState.SingleCurrency.Content -> {
|
||||
analyticsEventHandler.send(PortfolioEvent.Refreshed)
|
||||
refreshSingleCurrencyContent()
|
||||
}
|
||||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshMultiCurrencyContent() {
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
stateHolder.update(
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = true),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val maybeFetchResult = if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
|
||||
fetchCardTokenListUseCase(userWalletId = userWallet.walletId, refresh = true)
|
||||
} else {
|
||||
fetchTokenListUseCase(userWalletId = userWallet.walletId, refresh = true)
|
||||
}
|
||||
|
||||
maybeFetchResult.onLeft {
|
||||
stateHolder.update(SetTokenListErrorTransformer(userWalletId = userWallet.walletId, error = it))
|
||||
}
|
||||
|
||||
stateHolder.update(
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onReloadClick() {
|
||||
// TODO
|
||||
refreshSingleCurrencyContent()
|
||||
}
|
||||
|
||||
// FIXME: refreshSingleCurrencyContent mustn't update the TxHistory and Buttons. It only must fetch primary
|
||||
// currency. Now it not works because GetPrimaryCurrency's subscriber uses .distinctUntilChanged()
|
||||
private fun refreshSingleCurrencyContent() {
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
stateHolder.update(
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = true),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
fetchCurrencyStatusUseCase(userWallet.walletId, refresh = true)
|
||||
|
||||
// TODO:
|
||||
// walletScreenContentLoader.load(
|
||||
// userWallet = userWallet,
|
||||
// appCurrency = getSelectedAppCurrencyUseCase.unwrap(),
|
||||
// clickIntents = this@WalletClickIntentsV2,
|
||||
// coroutineScope = viewModelScope,
|
||||
// isRefresh = true,
|
||||
// )
|
||||
|
||||
stateHolder.update(
|
||||
SetRefreshStateTransformer(userWalletId = userWallet.walletId, isRefreshing = false),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,27 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.TokensAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenActionsState
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.PortfolioEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.CloseBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.OpenBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.MultiWalletCurrencyActionsConverter
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface WalletContentClickIntents {
|
||||
|
|
@ -21,33 +41,81 @@ internal interface WalletContentClickIntents {
|
|||
fun onTransactionClick(txHash: String)
|
||||
}
|
||||
|
||||
internal class WalletContentClickIntentsImplementor @Inject constructor() : WalletContentClickIntents {
|
||||
@Suppress("LongParameterList")
|
||||
internal class WalletContentClickIntentsImplementor @Inject constructor(
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val currencyActionsClickIntentsImplementor: WalletCurrencyActionsClickIntentsImplementor,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
|
||||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
) : BaseWalletClickIntents(), WalletContentClickIntents {
|
||||
|
||||
override fun onBackClick() {
|
||||
// TODO
|
||||
}
|
||||
override fun onBackClick() = router.popBackStack()
|
||||
|
||||
override fun onDetailsClick() {
|
||||
// TODO
|
||||
}
|
||||
override fun onDetailsClick() = router.openDetailsScreen()
|
||||
|
||||
override fun onManageTokensClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(PortfolioEvent.ButtonManageTokens)
|
||||
reduxStateHolder.dispatch(action = TokensAction.SetArgs.ManageAccess)
|
||||
router.openManageTokensScreen()
|
||||
}
|
||||
|
||||
override fun onOrganizeTokensClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(PortfolioEvent.OrganizeTokens)
|
||||
router.openOrganizeTokensScreen(userWalletId = stateHolder.getSelectedWalletId())
|
||||
}
|
||||
|
||||
override fun onTokenItemClick(currency: CryptoCurrency) {
|
||||
// TODO
|
||||
analyticsEventHandler.send(PortfolioEvent.TokenTapped)
|
||||
router.openTokenDetails(stateHolder.getSelectedWalletId(), currency)
|
||||
}
|
||||
|
||||
override fun onTokenItemLongClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
getCryptoCurrencyActionsUseCase(userWallet = userWallet, cryptoCurrencyStatus = cryptoCurrencyStatus)
|
||||
.take(count = 1)
|
||||
.collectLatest {
|
||||
showActionsBottomSheet(it, userWallet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showActionsBottomSheet(tokenActionsState: TokenActionsState, userWallet: UserWallet) {
|
||||
stateHolder.update(
|
||||
OpenBottomSheetTransformer(
|
||||
userWalletId = userWallet.walletId,
|
||||
content = ActionsBottomSheetConfig(
|
||||
actions = MultiWalletCurrencyActionsConverter(
|
||||
userWallet = userWallet,
|
||||
clickIntents = currencyActionsClickIntentsImplementor,
|
||||
).convert(tokenActionsState),
|
||||
),
|
||||
onDismissBottomSheet = {
|
||||
stateHolder.update(
|
||||
CloseBottomSheetTransformer(userWalletId = userWallet.walletId),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTransactionClick(txHash: String) {
|
||||
// TODO
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val currency = getPrimaryCurrencyStatusUpdatesUseCase.unwrap(
|
||||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
)
|
||||
?.currency
|
||||
?: return@launch
|
||||
|
||||
router.openUrl(
|
||||
url = getExplorerTransactionUrlUseCase(txHash = txHash, networkId = currency.network.id),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,46 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.WrappedList
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.IsCryptoCurrencyCoinCouldHideUseCase
|
||||
import com.tangem.domain.tokens.RemoveCurrencyUseCase
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent
|
||||
import com.tangem.domain.tokens.models.analytics.TokenScreenAnalyticsEvent
|
||||
import com.tangem.domain.walletconnect.WalletConnectActions
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.CloseBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.OpenBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
interface WalletCurrencyActionsClickIntents {
|
||||
|
|
@ -24,41 +64,353 @@ interface WalletCurrencyActionsClickIntents {
|
|||
fun onExploreClick()
|
||||
}
|
||||
|
||||
internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor() : WalletCurrencyActionsClickIntents {
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val walletEventSender: WalletEventSender,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val isCryptoCurrencyCoinCouldHide: IsCryptoCurrencyCoinCouldHideUseCase,
|
||||
private val removeCurrencyUseCase: RemoveCurrencyUseCase,
|
||||
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
|
||||
private val getExploreUrlUseCase: GetExploreUrlUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents {
|
||||
|
||||
override fun onSendClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonSend(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWallet.walletId))
|
||||
|
||||
when (val currency = cryptoCurrencyStatus.currency) {
|
||||
is CryptoCurrency.Coin -> sendCoin(cryptoCurrencyStatus, userWallet)
|
||||
is CryptoCurrency.Token -> sendToken(currency, cryptoCurrencyStatus.value, userWallet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendCoin(cryptoCurrencyStatus: CryptoCurrencyStatus, userWallet: UserWallet) {
|
||||
reduxStateHolder.dispatch(
|
||||
action = TradeCryptoAction.New.SendCoin(userWallet = userWallet, coinStatus = cryptoCurrencyStatus),
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendToken(
|
||||
cryptoCurrency: CryptoCurrency.Token,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus.Status,
|
||||
userWallet: UserWallet,
|
||||
) {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
getNetworkCoinStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
networkId = cryptoCurrency.network.id,
|
||||
derivationPath = cryptoCurrency.network.derivationPath,
|
||||
isSingleWalletWithTokens = userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
|
||||
)
|
||||
.take(count = 1)
|
||||
.collectLatest {
|
||||
it.onRight { coinStatus ->
|
||||
reduxStateHolder.dispatch(
|
||||
action = TradeCryptoAction.New.SendToken(
|
||||
userWallet = userWallet,
|
||||
tokenCurrency = cryptoCurrency,
|
||||
tokenFiatRate = cryptoCurrencyStatus.fiatRate,
|
||||
coinFiatRate = coinStatus.value.fiatRate,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonReceive(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val currency = cryptoCurrencyStatus.currency
|
||||
val addresses = walletManagersFacade.getAddress(userWalletId = userWalletId, network = currency.network)
|
||||
|
||||
analyticsEventHandler.send(event = TokenReceiveAnalyticsEvent.ReceiveScreenOpened)
|
||||
|
||||
stateHolder.update(
|
||||
OpenBottomSheetTransformer(
|
||||
userWalletId = userWalletId,
|
||||
content = createReceiveBottomSheetContent(currency, addresses),
|
||||
onDismissBottomSheet = {
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWalletId))
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createReceiveBottomSheetContent(
|
||||
currency: CryptoCurrency,
|
||||
addresses: List<Address>,
|
||||
): TangemBottomSheetConfigContent {
|
||||
return TokenReceiveBottomSheetConfig(
|
||||
name = currency.name,
|
||||
symbol = currency.symbol,
|
||||
network = currency.network.name,
|
||||
addresses = addresses.map { address ->
|
||||
AddressModel(
|
||||
value = address.value,
|
||||
type = AddressModel.Type.valueOf(address.type.name),
|
||||
)
|
||||
},
|
||||
onCopyClick = {
|
||||
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonCopyAddress(currency.symbol))
|
||||
},
|
||||
onShareClick = {
|
||||
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonShareAddress(currency.symbol))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCopyAddressClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonCopyAddress(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
walletManagersFacade.getAddress(
|
||||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
)
|
||||
.find { it.type == AddressType.Default }
|
||||
?.value
|
||||
?.let {
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.CopyAddress(
|
||||
address = it,
|
||||
toast = resourceReference(R.string.wallet_notification_address_copied),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHideTokensClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonRemoveToken(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.ShowAlert(
|
||||
state = getHideTokeAlertConfig(stateHolder.getSelectedWalletId(), cryptoCurrencyStatus),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getHideTokeAlertConfig(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): WalletAlertState.DefaultAlert {
|
||||
val currency = cryptoCurrencyStatus.currency
|
||||
return if (currency is CryptoCurrency.Coin && !isCryptoCurrencyCoinCouldHide(userWalletId, currency)) {
|
||||
WalletAlertState.DefaultAlert(
|
||||
title = resourceReference(
|
||||
id = R.string.token_details_unable_hide_alert_title,
|
||||
formatArgs = WrappedList(listOf(cryptoCurrencyStatus.currency.name)),
|
||||
),
|
||||
message = resourceReference(
|
||||
id = R.string.token_details_unable_hide_alert_message,
|
||||
formatArgs = WrappedList(
|
||||
listOf(
|
||||
cryptoCurrencyStatus.currency.name,
|
||||
cryptoCurrencyStatus.currency.network.name,
|
||||
),
|
||||
),
|
||||
),
|
||||
onConfirmClick = null,
|
||||
)
|
||||
} else {
|
||||
WalletAlertState.DefaultAlert(
|
||||
title = resourceReference(
|
||||
id = R.string.token_details_hide_alert_title,
|
||||
formatArgs = WrappedList(listOf(cryptoCurrencyStatus.currency.name)),
|
||||
),
|
||||
message = resourceReference(R.string.token_details_hide_alert_message),
|
||||
onConfirmClick = { onPerformHideToken(cryptoCurrencyStatus) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPerformHideToken(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
removeCurrencyUseCase(userWalletId, cryptoCurrencyStatus.currency)
|
||||
.fold(
|
||||
ifLeft = {
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.ShowToast(text = resourceReference(R.string.common_error)),
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
getSelectedWalletSyncUseCase.unwrap()?.let { userWallet ->
|
||||
reduxStateHolder.dispatch(
|
||||
action = WalletConnectActions.New.SetupUserChains(userWallet = userWallet),
|
||||
)
|
||||
}
|
||||
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWalletId))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSellClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonSell(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
showErrorIfDemoModeOrElse {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
reduxStateHolder.dispatch(
|
||||
action = TradeCryptoAction.New.Sell(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
appCurrencyCode = getSelectedAppCurrencyUseCase.unwrap().code,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBuyClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonBuy(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
showErrorIfDemoModeOrElse {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
reduxStateHolder.dispatch(
|
||||
TradeCryptoAction.New.Buy(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
appCurrencyCode = getSelectedAppCurrencyUseCase.unwrap().code,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
// TODO
|
||||
analyticsEventHandler.send(
|
||||
event = TokenScreenAnalyticsEvent.ButtonExchange(cryptoCurrencyStatus.currency.symbol),
|
||||
)
|
||||
|
||||
reduxStateHolder.dispatch(TradeCryptoAction.New.Swap(cryptoCurrencyStatus.currency))
|
||||
}
|
||||
|
||||
override fun onExploreClick() {
|
||||
// TODO
|
||||
showErrorIfDemoModeOrElse(action = ::openExplorer)
|
||||
}
|
||||
|
||||
private fun openExplorer() {
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val currency = getPrimaryCurrencyStatusUpdatesUseCase.unwrap(userWalletId)?.currency ?: return@launch
|
||||
val addresses = walletManagersFacade.getAddress(userWalletId = userWalletId, network = currency.network)
|
||||
|
||||
if (addresses.size == 1) {
|
||||
router.openUrl(
|
||||
url = getExploreUrlUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
addressType = AddressType.Default,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
showChooseAddressBottomSheet(userWalletId, addresses, currency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showChooseAddressBottomSheet(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<Address>,
|
||||
currency: CryptoCurrency,
|
||||
) {
|
||||
stateHolder.update(
|
||||
OpenBottomSheetTransformer(
|
||||
userWalletId = userWalletId,
|
||||
content = ChooseAddressBottomSheetConfig(
|
||||
addressModels = addresses
|
||||
.map { address ->
|
||||
AddressModel(
|
||||
value = address.value,
|
||||
type = AddressModel.Type.valueOf(address.type.name),
|
||||
)
|
||||
}
|
||||
.toImmutableList(),
|
||||
onClick = {
|
||||
onAddressTypeSelected(
|
||||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
addressModel = it,
|
||||
)
|
||||
},
|
||||
),
|
||||
onDismissBottomSheet = {
|
||||
stateHolder.update(
|
||||
CloseBottomSheetTransformer(userWalletId = userWalletId),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onAddressTypeSelected(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
addressModel: AddressModel,
|
||||
) {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
router.openUrl(
|
||||
url = getExploreUrlUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
addressType = AddressType.valueOf(addressModel.type.name),
|
||||
),
|
||||
)
|
||||
|
||||
stateHolder.update(
|
||||
CloseBottomSheetTransformer(userWalletId = userWalletId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showErrorIfDemoModeOrElse(action: () -> Unit) {
|
||||
val cardId = getSelectedWalletSyncUseCase.unwrap()?.cardId ?: return
|
||||
|
||||
if (isDemoCardUseCase(cardId = cardId)) {
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = stateHolder.getSelectedWalletId()))
|
||||
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.ShowError(
|
||||
text = resourceReference(id = R.string.alert_demo_feature_disabled),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,44 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents
|
||||
|
||||
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
||||
import com.tangem.domain.card.SetCardWasScannedUseCase
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.LegacyAction
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.settings.NeverToSuggestRateAppUseCase
|
||||
import com.tangem.domain.settings.RemindToRateAppLaterUseCase
|
||||
import com.tangem.domain.tokens.FetchTokenListUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UnlockWalletsError
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.UnlockWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.UpdateWalletUseCase
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.Basic
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.ScanCardToUnlockWalletClickHandler
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.ScanCardToUnlockWalletError
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.unwrap
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateHolderV2
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.CloseBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.OpenBottomSheetTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface WalletWarningsClickIntents {
|
||||
|
|
@ -24,41 +62,224 @@ internal interface WalletWarningsClickIntents {
|
|||
fun onCloseRateAppWarningClick()
|
||||
}
|
||||
|
||||
internal class WalletWarningsClickIntentsImplementer @Inject constructor() : WalletWarningsClickIntents {
|
||||
@Suppress("LongParameterList")
|
||||
internal class WalletWarningsClickIntentsImplementer @Inject constructor(
|
||||
private val stateHolder: WalletStateHolderV2,
|
||||
private val walletEventSender: WalletEventSender,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val updateWalletUseCase: UpdateWalletUseCase,
|
||||
private val unlockWalletsUseCase: UnlockWalletsUseCase,
|
||||
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
|
||||
private val scanCardToUnlockWalletClickHandler: ScanCardToUnlockWalletClickHandler,
|
||||
private val fetchTokenListUseCase: FetchTokenListUseCase,
|
||||
private val setCardWasScannedUseCase: SetCardWasScannedUseCase,
|
||||
private val neverToSuggestRateAppUseCase: NeverToSuggestRateAppUseCase,
|
||||
private val remindToRateAppLaterUseCase: RemindToRateAppLaterUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : BaseWalletClickIntents(), WalletWarningsClickIntents {
|
||||
|
||||
override fun onAddBackupCardClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(MainScreen.NoticeBackupYourWalletTapped)
|
||||
router.openOnboardingScreen()
|
||||
}
|
||||
|
||||
override fun onCloseAlreadySignedHashesWarningClick() {
|
||||
// TODO
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
setCardWasScannedUseCase(cardId = userWallet.cardId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGenerateMissedAddressesClick(missedAddressCurrencies: List<CryptoCurrency>) {
|
||||
// TODO
|
||||
val userWallet = getSelectedWalletSyncUseCase.unwrap() ?: return
|
||||
|
||||
analyticsEventHandler.send(Basic.CardWasScanned(AnalyticsParam.ScannedFrom.Main))
|
||||
analyticsEventHandler.send(MainScreen.NoticeScanYourCardTapped)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
deriveMissingCurrencies(
|
||||
scanResponse = userWallet.scanResponse,
|
||||
currencyList = missedAddressCurrencies,
|
||||
) { scannedCardResponse ->
|
||||
updateWalletUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
update = { it.copy(scanResponse = scannedCardResponse) },
|
||||
)
|
||||
.onRight { fetchTokenListUseCase(userWalletId = it.walletId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
private fun deriveMissingCurrencies(
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<CryptoCurrency>,
|
||||
onSuccess: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
config.primaryCurve(blockchain = Blockchain.fromId(it.network.id.value))?.let { curve ->
|
||||
getNewDerivations(curve, scanResponse, it)
|
||||
}
|
||||
}
|
||||
|
||||
val derivations = buildMap<ByteArrayKey, MutableList<DerivationPath>> {
|
||||
derivationDataList.forEach {
|
||||
val current = this[it.derivations.first]
|
||||
if (current != null) {
|
||||
current.addAll(it.derivations.second)
|
||||
current.distinct()
|
||||
} else {
|
||||
this[it.derivations.first] = it.derivations.second.toMutableList()
|
||||
}
|
||||
}
|
||||
}.ifEmpty { return }
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
derivePublicKeysUseCase(cardId = null, derivations = derivations)
|
||||
.onRight {
|
||||
val newDerivedKeys = it.entries
|
||||
val oldDerivedKeys = scanResponse.derivedKeys
|
||||
|
||||
val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet()
|
||||
|
||||
val updatedDerivedKeys = walletKeys.associateWith { walletKey ->
|
||||
val oldDerivations = ExtendedPublicKeysMap(oldDerivedKeys[walletKey] ?: emptyMap())
|
||||
val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||
ExtendedPublicKeysMap(oldDerivations + newDerivations)
|
||||
}
|
||||
val updatedScanResponse = scanResponse.copy(derivedKeys = updatedDerivedKeys)
|
||||
|
||||
onSuccess(updatedScanResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNewDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currency: CryptoCurrency,
|
||||
): DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val blockchain = Blockchain.fromId(currency.network.id.value)
|
||||
val supportedCurves = blockchain.getSupportedCurves()
|
||||
val path = blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val customPath = currency.network.derivationPath.value?.let {
|
||||
DerivationPath(it)
|
||||
}.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
if (currency is CryptoCurrency.Coin && blockchain == Blockchain.Cardano) {
|
||||
currency.network.derivationPath.value?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
}
|
||||
|
||||
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
|
||||
val alreadyDerivedKeys: ExtendedPublicKeysMap =
|
||||
scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||
val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
|
||||
|
||||
val toDerive = bothCandidates.filterNot { alreadyDerivedPaths.contains(it) }
|
||||
if (toDerive.isEmpty()) return null
|
||||
|
||||
return DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
|
||||
}
|
||||
|
||||
class DerivationData(val derivations: Pair<ByteArrayKey, List<DerivationPath>>)
|
||||
|
||||
override fun onOpenUnlockWalletsBottomSheetClick() {
|
||||
// TODO
|
||||
stateHolder.update(
|
||||
OpenBottomSheetTransformer(
|
||||
content = requireNotNull(stateHolder.getSelectedWallet().bottomSheetConfig).content,
|
||||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
onDismissBottomSheet = {
|
||||
stateHolder.update(
|
||||
CloseBottomSheetTransformer(userWalletId = stateHolder.getSelectedWalletId()),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onUnlockWalletClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(MainScreen.NoticeWalletLocked)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
unlockWalletsUseCase(throwIfNotAllWalletsUnlocked = true)
|
||||
.onRight { stateHolder.update(CloseBottomSheetTransformer(stateHolder.getSelectedWalletId())) }
|
||||
.onLeft(::handleUnlockWalletsError)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUnlockWalletsError(error: UnlockWalletsError) {
|
||||
val event = when (error) {
|
||||
is UnlockWalletsError.DataError,
|
||||
is UnlockWalletsError.UnableToUnlockWallets,
|
||||
-> WalletEvent.ShowToast(resourceReference(R.string.user_wallet_list_error_unable_to_unlock))
|
||||
is UnlockWalletsError.NoUserWalletSelected,
|
||||
is UnlockWalletsError.NotAllUserWalletsUnlocked,
|
||||
-> WalletEvent.ShowAlert(WalletAlertState.RescanWallets)
|
||||
}
|
||||
|
||||
walletEventSender.send(event)
|
||||
}
|
||||
|
||||
override fun onScanToUnlockWalletClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(event = MainScreen.WalletUnlockTapped)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
scanCardToUnlockWalletClickHandler(walletId = stateHolder.getSelectedWalletId())
|
||||
.onLeft { error ->
|
||||
when (error) {
|
||||
ScanCardToUnlockWalletError.WrongCardIsScanned -> {
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.ShowAlert(WalletAlertState.WrongCardIsScanned),
|
||||
)
|
||||
}
|
||||
ScanCardToUnlockWalletError.ManyScanFails -> router.openScanFailedDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLikeAppClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Liked))
|
||||
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.RateApp(
|
||||
onDismissClick = {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
neverToSuggestRateAppUseCase()
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDislikeAppClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked))
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
neverToSuggestRateAppUseCase()
|
||||
|
||||
reduxStateHolder.dispatch(LegacyAction.SendEmailRateCanBeBetter)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCloseRateAppWarningClick() {
|
||||
// TODO
|
||||
analyticsEventHandler.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Closed))
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
remindToRateAppLaterUseCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue