Skip to content

Commit

Permalink
feat(staking): AND-6779 txflow pkw toggle + fix interstitial (#4177)
Browse files Browse the repository at this point in the history
  • Loading branch information
dserrano-bc committed Dec 6, 2022
1 parent 0ee6cce commit 5601ca1
Show file tree
Hide file tree
Showing 15 changed files with 218 additions and 69 deletions.
Expand Up @@ -699,6 +699,23 @@ sealed class TransactionIntent : MviIntent<TransactionState> {
)
}

class UpdatePrivateKeyAccountsFilterState(private val isPkwAccountFilterActive: Boolean) : TransactionIntent() {
override fun reduce(oldState: TransactionState): TransactionState =
oldState.copy(
isPkwAccountFilterActive = isPkwAccountFilterActive
)
}

class UpdatePrivateKeyFilter(val isPkwAccountFilterActive: Boolean) : TransactionIntent() {
override fun reduce(oldState: TransactionState): TransactionState =
oldState.copy(
isPkwAccountFilterActive = isPkwAccountFilterActive
)

override fun isValidFor(oldState: TransactionState): Boolean =
isPkwAccountFilterActive != oldState.isPkwAccountFilterActive
}

object LoadDepositTerms : TransactionIntent() {

override fun isValidFor(oldState: TransactionState): Boolean = oldState.depositTerms == null
Expand Down
Expand Up @@ -152,6 +152,7 @@ data class TransactionState(
val quickFillButtonData: QuickFillButtonData? = null,
val amountsToPrefill: PrefillAmounts? = null,
val canFilterOutTradingAccounts: Boolean = false,
val isPkwAccountFilterActive: Boolean = false,
val quickFillRoundingData: List<QuickFillRoundingData> = emptyList(),
val isLoading: Boolean = false,
val ffImprovedPaymentUxEnabled: Boolean = false,
Expand Down Expand Up @@ -385,7 +386,21 @@ class TransactionModel(
null
}
is TransactionIntent.ShowSourceSelection ->
loadAvailableSourceAccounts(previousState.action, previousState.selectedTarget, true)
loadAvailableSourceAccounts(
action = previousState.action,
transactionTarget = previousState.selectedTarget,
shouldResetBackStack = true,
shouldShowPkwOnTrading = interactor.shouldShowPkwOnTradingMode()
)
is TransactionIntent.UpdatePrivateKeyFilter -> {
interactor.updatePkwFilterState(intent.isPkwAccountFilterActive)
loadAvailableSourceAccounts(
action = previousState.action,
transactionTarget = previousState.selectedTarget,
shouldResetBackStack = true,
shouldShowPkwOnTrading = interactor.shouldShowPkwOnTradingMode()
)
}
is TransactionIntent.LinkBankInfoSuccess,
is TransactionIntent.LinkBankFailed,
is TransactionIntent.ClearBackStack,
Expand Down Expand Up @@ -423,7 +438,8 @@ class TransactionModel(
is TransactionIntent.UpdatePasswordIsValidated,
is TransactionIntent.UpdatePasswordNotValidated,
is TransactionIntent.PrepareTransaction,
is TransactionIntent.AvailableSourceAccountsListUpdated -> null
is TransactionIntent.AvailableSourceAccountsListUpdated,
is TransactionIntent.UpdatePrivateKeyAccountsFilterState -> null
}
}

Expand Down Expand Up @@ -481,14 +497,14 @@ class TransactionModel(
process(TransactionIntent.TargetSelected)
null
}?.doOnSuccess { accounts ->
process(
TransactionIntent.UpdateTradingAccountsFilterState(
canFilterTradingAccounts = accounts.any { it is TradingAccount } &&
accounts.any { it is NonCustodialAccount } &&
action == AssetAction.Swap &&
walletModeService.enabledWalletMode() != WalletMode.UNIVERSAL
if (action == AssetAction.Swap && walletModeService.enabledWalletMode() != WalletMode.UNIVERSAL) {
process(
TransactionIntent.UpdateTradingAccountsFilterState(
canFilterTradingAccounts = accounts.any { it is TradingAccount } &&
accounts.any { it is NonCustodialAccount }
)
)
)
}
}

private fun Single<List<SingleAccount>>.processTargets(
Expand Down Expand Up @@ -520,41 +536,72 @@ class TransactionModel(
action: AssetAction,
transactionTarget: TransactionTarget,
shouldResetBackStack: Boolean = false
): Disposable =
if (action == AssetAction.StakingDeposit) {
Singles.zip(
fetchProductEligibility(action, NullCryptoAccount(), transactionTarget).toSingle(),
interactor.getAvailableSourceAccounts(action, transactionTarget)
).subscribeBy(
onSuccess = { (access, accountList) ->
if (access is FeatureAccess.Blocked) {
process(TransactionIntent.ShowFeatureBlocked(access.reason))
} else {
process(
TransactionIntent.AvailableSourceAccountsListUpdated(accountList)
)
}
if (shouldResetBackStack) {
process(TransactionIntent.ClearBackStack)
}
},
onError = {
process(TransactionIntent.FatalTransactionError(it))
}
): Disposable {
val shouldShowPkwOnTrading = interactor.shouldShowPkwOnTradingMode()
process(TransactionIntent.UpdatePrivateKeyAccountsFilterState(shouldShowPkwOnTrading))

return if (action == AssetAction.StakingDeposit) {
checkWithdrawalNoticeAndProceed(
action = action,
transactionTarget = transactionTarget,
shouldResetBackStack = shouldResetBackStack,
shouldShowPkwOnTrading = shouldShowPkwOnTrading
)
} else {
loadAvailableSourceAccounts(action, transactionTarget, shouldResetBackStack)
loadAvailableSourceAccounts(
action = action,
transactionTarget = transactionTarget,
shouldResetBackStack = shouldResetBackStack,
shouldShowPkwOnTrading = shouldShowPkwOnTrading
)
}
}

private fun checkWithdrawalNoticeAndProceed(
action: AssetAction,
transactionTarget: TransactionTarget,
shouldResetBackStack: Boolean,
shouldShowPkwOnTrading: Boolean
) = Singles.zip(
fetchProductEligibility(action, NullCryptoAccount(), transactionTarget).toSingle(),
interactor.getAvailableSourceAccounts(action, transactionTarget)
).subscribeBy(
onSuccess = { (access, accountList) ->
if (access is FeatureAccess.Blocked) {
process(TransactionIntent.ShowFeatureBlocked(access.reason))
} else {
process(
TransactionIntent.AvailableSourceAccountsListUpdated(
accountList.filter {
shouldShowPkwOnTrading || it !is NonCustodialAccount
}
)
)
}

if (shouldResetBackStack) {
process(TransactionIntent.ClearBackStack)
}
},
onError = {
process(TransactionIntent.FatalTransactionError(it))
}
)

private fun loadAvailableSourceAccounts(
action: AssetAction,
transactionTarget: TransactionTarget,
shouldResetBackStack: Boolean
shouldResetBackStack: Boolean,
shouldShowPkwOnTrading: Boolean
) = interactor.getAvailableSourceAccounts(action, transactionTarget)
.subscribeBy(
onSuccess = {
onSuccess = { accountList ->
process(
TransactionIntent.AvailableSourceAccountsListUpdated(it)
TransactionIntent.AvailableSourceAccountsListUpdated(
accountList.filter {
shouldShowPkwOnTrading || it !is NonCustodialAccount
}
)
)
if (shouldResetBackStack) {
process(TransactionIntent.ClearBackStack)
Expand Down Expand Up @@ -664,6 +711,7 @@ class TransactionModel(
AssetAction.FiatWithdraw -> interactor.userAccessForFeature(Feature.WithdrawFiat).toMaybe()
AssetAction.FiatDeposit -> interactor.userAccessForFeature(Feature.DepositFiat).toMaybe()
AssetAction.StakingDeposit -> interactor.checkShouldShowInterstitial(
sourceAccount = sourceAccount,
asset = (target as CryptoAccount).currency,
feature = Feature.DepositStaking
).toMaybe()
Expand Down
Expand Up @@ -3,12 +3,14 @@ package piuk.blockchain.android.ui.transactionflow.engine
import com.blockchain.banking.BankPaymentApproval
import com.blockchain.coincore.AddressFactory
import com.blockchain.coincore.AssetAction
import com.blockchain.coincore.AssetFilter
import com.blockchain.coincore.BlockchainAccount
import com.blockchain.coincore.Coincore
import com.blockchain.coincore.CryptoAccount
import com.blockchain.coincore.FeeLevel
import com.blockchain.coincore.FiatAccount
import com.blockchain.coincore.InterestAccount
import com.blockchain.coincore.NullCryptoAccount
import com.blockchain.coincore.PendingTx
import com.blockchain.coincore.ReceiveAddress
import com.blockchain.coincore.SingleAccount
Expand Down Expand Up @@ -40,6 +42,7 @@ import com.blockchain.nabu.datamanagers.repositories.swap.CustodialRepository
import com.blockchain.preferences.BankLinkingPrefs
import com.blockchain.preferences.CurrencyPrefs
import com.blockchain.preferences.LocalSettingsPrefs
import com.blockchain.preferences.TransactionPrefs
import com.blockchain.store.asSingle
import com.blockchain.utils.mapList
import com.blockchain.utils.rxSingleOutcome
Expand Down Expand Up @@ -93,7 +96,8 @@ class TransactionInteractor(
private val localSettingsPrefs: LocalSettingsPrefs,
private val improvedPaymentUxFF: FeatureFlag,
private val dynamicAssetRepository: UniversalDynamicAssetRepository,
private val stakingService: StakingService
private val stakingService: StakingService,
private val transactionPrefs: TransactionPrefs
) {
private var transactionProcessor: TransactionProcessor? = null
private val invalidate = PublishSubject.create<Unit>()
Expand Down Expand Up @@ -219,6 +223,7 @@ class TransactionInteractor(
require(targetAccount is CryptoAccount)
coincore.walletsWithActions(
actions = setOf(action),
filter = AssetFilter.All,
sorter = defaultAccountsSorting.sorter()
).map {
it.filter { acc ->
Expand All @@ -234,6 +239,7 @@ class TransactionInteractor(
require(targetAccount is CryptoAccount)
coincore.walletsWithActions(
actions = setOf(action),
filter = AssetFilter.All,
sorter = defaultAccountsSorting.sorter()
).map {
it.filter { acc ->
Expand All @@ -251,6 +257,13 @@ class TransactionInteractor(
else -> throw IllegalStateException("Source account should be preselected for action $action")
}

fun shouldShowPkwOnTradingMode(): Boolean =
transactionPrefs.showPkwAccountsOnTradingMode

fun updatePkwFilterState(showPkwOnTradingMode: Boolean) {
transactionPrefs.showPkwAccountsOnTradingMode = showPkwOnTradingMode
}

private fun filterDustBalances(accountList: List<CryptoAccount>) =
accountList.map { account ->
account.balanceRx
Expand Down Expand Up @@ -408,20 +421,28 @@ class TransactionInteractor(
fun userAccessForFeature(feature: Feature): Single<FeatureAccess> =
identity.userAccessForFeature(feature)

fun checkShouldShowInterstitial(asset: AssetInfo, feature: Feature): Single<FeatureAccess> =
stakingService.getLimitsForAsset(asset).asSingle().flatMap { limits ->
if (limits.withdrawalsDisabled) {
stakingService.getBalanceForAsset(asset).asSingle().map { accountBalance ->
if (accountBalance.totalBalance.isZero) {
FeatureAccess.Blocked(
BlockedReason.ShouldAcknowledgeStakingWithdrawal(
assetIconUrl = asset.logo
fun checkShouldShowInterstitial(
sourceAccount: BlockchainAccount,
asset: AssetInfo,
feature: Feature
): Single<FeatureAccess> =
if (sourceAccount !is NullCryptoAccount) {
Single.just(FeatureAccess.Granted())
} else {
stakingService.getLimitsForAsset(asset).asSingle().flatMap { limits ->
if (limits.withdrawalsDisabled) {
stakingService.getBalanceForAsset(asset).asSingle().map { accountBalance ->
if (accountBalance.totalBalance.isZero) {
FeatureAccess.Blocked(
BlockedReason.ShouldAcknowledgeStakingWithdrawal(
assetIconUrl = asset.logo
)
)
)
} else FeatureAccess.Granted()
} else FeatureAccess.Granted()
}
} else {
identity.userAccessForFeature(feature)
}
} else {
identity.userAccessForFeature(feature)
}
}

Expand Down
Expand Up @@ -76,13 +76,20 @@ class SelectSourceAccountFragment :
}
}

assetAction?.let {
if (customiser.selectSourceShouldHaveSearch(it)) {
binding.setupSearch()
} else {
with(binding) {
with(binding) {
assetAction?.let {
if (customiser.selectSourceShouldHaveSearch(it)) {
setupSearch()
} else {
sourceSelectSearch.gone()
}

if (customiser.shouldShowSourceAccountWalletsSwitch(it)) {
pkwSwitchLayout.visible()
pkwAccountsSwitch.onCheckChanged = { isChecked ->
model.process(TransactionIntent.UpdatePrivateKeyFilter(isChecked))
}
}
}
}
}
Expand Down Expand Up @@ -120,6 +127,8 @@ class SelectSourceAccountFragment :

availableSources = newState.availableSources
linkingBankState = newState.linkBankState

binding.pkwAccountsSwitch.isChecked = newState.isPkwAccountFilterActive
}

private fun FragmentTxAccountSelectorBinding.setupSearch() {
Expand Down
Expand Up @@ -15,4 +15,5 @@ interface SourceSelectionCustomisations {
fun sourceAccountSelectionStatusDecorator(state: TransactionState): StatusDecorator
fun getLinkingSourceForAction(state: TransactionState): BankAuthSource
fun selectSourceShouldHaveSearch(action: AssetAction): Boolean
fun shouldShowSourceAccountWalletsSwitch(action: AssetAction): Boolean
}
Expand Up @@ -27,6 +27,7 @@ import com.blockchain.domain.common.model.ServerErrorAction
import com.blockchain.nabu.BlockedReason
import com.blockchain.nabu.datamanagers.TransactionError
import com.blockchain.nabu.models.responses.simplebuy.BuySellOrderResponse
import com.blockchain.walletmode.WalletMode
import com.blockchain.walletmode.WalletModeService
import info.blockchain.balance.CryptoValue
import info.blockchain.balance.Currency
Expand Down Expand Up @@ -1397,6 +1398,13 @@ class TransactionFlowCustomiserImpl(
else -> false
}

override fun shouldShowSourceAccountWalletsSwitch(action: AssetAction): Boolean =
when (action) {
AssetAction.StakingDeposit,
AssetAction.InterestDeposit -> walletModeService.enabledWalletMode() != WalletMode.UNIVERSAL
else -> false
}

override fun getBackNavigationAction(state: TransactionState): BackNavigationState =
when (state.currentStep) {
TransactionStep.ENTER_ADDRESS -> BackNavigationState.ClearTransactionTarget
Expand Down
Expand Up @@ -241,7 +241,8 @@ val transactionModule = module {
localSettingsPrefs = get(),
improvedPaymentUxFF = payloadScope.get(improvedPaymentUxFeatureFlag),
dynamicAssetRepository = payloadScope.get(),
stakingService = payloadScope.get()
stakingService = payloadScope.get(),
transactionPrefs = payloadScope.get()
)
}

Expand Down

0 comments on commit 5601ca1

Please sign in to comment.