mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 20:45:53 +00:00
Move Pending Signatures from the wallet home screen to the Bridge screen
Wrong screen in the previous commit - moved it to sit right below the existing per-leg renewal sign buttons on the Bridge input screen, which is where it was actually asked for: a signatory renewing their own wUSDT/Polkadot USDT allowance there should also see (and be able to jump to) other pending multisig operations - e.g. someone else's large bridge swap - waiting on their signature, without navigating elsewhere. BalanceListFragment/ViewModel/Module are reverted to their prior state. The reusable pieces (PendingSignatureModel, item_pending_signature_row layout) are kept and repurposed for the Bridge screen; the RecyclerView SingleItemAdapter/card layout built for the home screen are removed since Bridge is a plain (non-RecyclerView) fragment - rows are inflated directly into a LinearLayout container instead, same underlying data and MultisigCallFormatter reuse as before. The feature-assets -> feature-multisig:operations dependency and the FeatureApi wiring (AssetsFeatureComponent/Dependencies/Holder) from the previous commit stay as-is - Bridge is the same Gradle module, so no change needed there.
This commit is contained in:
+1
-31
@@ -36,9 +36,6 @@ import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PezkuwiDashboardAdapter
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PezkuwiDashboardHolder
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PendingSignaturesAdapter
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PendingSignaturesHolder
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.model.PendingSignatureModel
|
||||
import io.novafoundation.nova.feature_assets.presentation.citizenship.CitizenshipBottomSheet
|
||||
import io.novafoundation.nova.feature_banners_api.presentation.BannerHolder
|
||||
import io.novafoundation.nova.feature_banners_api.presentation.PromotionBannerAdapter
|
||||
@@ -52,7 +49,6 @@ class BalanceListFragment :
|
||||
AssetsHeaderAdapter.Handler,
|
||||
ManageAssetsAdapter.Handler,
|
||||
PezkuwiDashboardAdapter.Handler,
|
||||
PendingSignaturesAdapter.Handler,
|
||||
CitizenshipBottomSheet.CitizenshipDismissListener {
|
||||
|
||||
override fun createBinding() = FragmentBalanceListBinding.inflate(layoutInflater)
|
||||
@@ -70,10 +66,6 @@ class BalanceListFragment :
|
||||
PezkuwiDashboardAdapter(this)
|
||||
}
|
||||
|
||||
private val pendingSignaturesAdapter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
PendingSignaturesAdapter(imageLoader, this)
|
||||
}
|
||||
|
||||
private val bannerAdapter: PromotionBannerAdapter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
PromotionBannerAdapter(closable = true)
|
||||
}
|
||||
@@ -94,15 +86,7 @@ class BalanceListFragment :
|
||||
}
|
||||
|
||||
private val adapter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
ConcatAdapter(
|
||||
headerAdapter,
|
||||
pezkuwiDashboardAdapter,
|
||||
pendingSignaturesAdapter,
|
||||
bannerAdapter,
|
||||
manageAssetsAdapter,
|
||||
emptyAssetsPlaceholder,
|
||||
assetsAdapter
|
||||
)
|
||||
ConcatAdapter(headerAdapter, pezkuwiDashboardAdapter, bannerAdapter, manageAssetsAdapter, emptyAssetsPlaceholder, assetsAdapter)
|
||||
}
|
||||
|
||||
override fun applyInsets(rootView: View) {
|
||||
@@ -159,11 +143,6 @@ class BalanceListFragment :
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.pendingSignaturesFlow.observe { models ->
|
||||
pendingSignaturesAdapter.setModels(models)
|
||||
pendingSignaturesAdapter.show(models.isNotEmpty())
|
||||
}
|
||||
|
||||
viewModel.bannersMixin.bindWithAdapter(bannerAdapter) {
|
||||
binder.balanceListAssets.invalidateItemDecorations()
|
||||
}
|
||||
@@ -322,10 +301,6 @@ class BalanceListFragment :
|
||||
viewModel.startTrackingClicked()
|
||||
}
|
||||
|
||||
override fun onSignClicked(model: PendingSignatureModel) {
|
||||
viewModel.pendingSignatureSignClicked(model)
|
||||
}
|
||||
|
||||
private fun setupRecyclerViewSpacing() {
|
||||
binder.balanceListAssets.addSpaceItemDecoration {
|
||||
add(SpaceBetween(AssetsHeaderHolder, PezkuwiDashboardHolder, spaceDp = 8))
|
||||
@@ -334,11 +309,6 @@ class BalanceListFragment :
|
||||
add(SpaceBetween(AssetsHeaderHolder, BannerHolder, spaceDp = 4))
|
||||
add(SpaceBetween(BannerHolder, ManageAssetsHolder, spaceDp = 4))
|
||||
add(SpaceBetween(AssetsHeaderHolder, ManageAssetsHolder, spaceDp = 24))
|
||||
|
||||
add(SpaceBetween(AssetsHeaderHolder, PendingSignaturesHolder, spaceDp = 8))
|
||||
add(SpaceBetween(PezkuwiDashboardHolder, PendingSignaturesHolder, spaceDp = 8))
|
||||
add(SpaceBetween(PendingSignaturesHolder, BannerHolder, spaceDp = 4))
|
||||
add(SpaceBetween(PendingSignaturesHolder, ManageAssetsHolder, spaceDp = 24))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-43
@@ -20,15 +20,10 @@ import io.novafoundation.nova.common.utils.formatting.formatAsPercentage
|
||||
import io.novafoundation.nova.common.utils.inBackground
|
||||
import io.novafoundation.nova.common.utils.launchUnit
|
||||
import io.novafoundation.nova.common.utils.withSafeLoading
|
||||
import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.MultisigPendingOperationsService
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.MultisigAction
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.PendingMultisigOperation
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.userAction
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.defaultSubstrateAddress
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.requireAccountIdKeyIn
|
||||
import io.novafoundation.nova.feature_assets.R
|
||||
import io.novafoundation.nova.feature_assets.domain.WalletInteractor
|
||||
import io.novafoundation.nova.feature_assets.domain.assets.list.AssetsListInteractor
|
||||
@@ -47,7 +42,6 @@ import io.novafoundation.nova.feature_assets.presentation.balance.common.buySell
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.common.buySell.BuySellSelectorMixinFactory
|
||||
import io.novafoundation.nova.feature_assets.presentation.citizenship.PendingCitizenshipReferrer
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.model.NftPreviewUi
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.model.PendingSignatureModel
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.model.TotalBalanceModel
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.AssetViewModeModel
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PendingOperationsCountModel
|
||||
@@ -58,10 +52,6 @@ import io.novafoundation.nova.feature_banners_api.presentation.source.assetsSour
|
||||
import io.novafoundation.nova.feature_currency_api.domain.CurrencyInteractor
|
||||
import io.novafoundation.nova.feature_currency_api.domain.model.Currency
|
||||
import io.novafoundation.nova.feature_currency_api.presentation.formatters.formatAsCurrency
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.callFormatting.MultisigCallFormatter
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.common.MultisigOperationPayload
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.common.fromOperationId
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.details.general.MultisigOperationDetailsPayload
|
||||
import io.novafoundation.nova.feature_nft_api.data.model.Nft
|
||||
import io.novafoundation.nova.feature_swap_api.domain.interactor.SwapAvailabilityInteractor
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.AmountFormatter
|
||||
@@ -118,7 +108,6 @@ class BalanceListViewModel(
|
||||
private val maskableValueFormatterProvider: MaskableValueFormatterProvider,
|
||||
private val buySellSelectorMixinFactory: BuySellSelectorMixinFactory,
|
||||
private val multisigPendingOperationsService: MultisigPendingOperationsService,
|
||||
private val multisigCallFormatter: MultisigCallFormatter,
|
||||
private val novaCardRestrictionCheckMixin: NovaCardRestrictionCheckMixin,
|
||||
private val maskingModeUseCase: MaskingModeUseCase,
|
||||
private val giftsRestrictionCheckMixin: GiftsRestrictionCheckMixin,
|
||||
@@ -259,38 +248,6 @@ class BalanceListViewModel(
|
||||
.combine(maskableAmountFormatterFlow, ::formatPendingOperationsCount)
|
||||
.shareInBackground()
|
||||
|
||||
val pendingSignaturesFlow = multisigPendingOperationsService.pendingOperations()
|
||||
.mapLatest { operations ->
|
||||
val account = selectedMetaAccount.first()
|
||||
|
||||
// Only operations still awaiting THIS signatory's own approval - once signed, the
|
||||
// item naturally drops out here on next sync (no client-side "turn green" state to
|
||||
// maintain in parallel with the real, authoritative on-chain approval status).
|
||||
operations
|
||||
.filter { it.userAction() is MultisigAction.CanApprove }
|
||||
.map { it.toPendingSignatureUi(account) }
|
||||
}
|
||||
.shareInBackground()
|
||||
|
||||
fun pendingSignatureSignClicked(model: PendingSignatureModel) {
|
||||
val operationPayload = MultisigOperationPayload.fromOperationId(model.id)
|
||||
router.openMultisigOperationDetails(MultisigOperationDetailsPayload(operationPayload))
|
||||
}
|
||||
|
||||
private suspend fun PendingMultisigOperation.toPendingSignatureUi(selectedAccount: MetaAccount): PendingSignatureModel {
|
||||
val initialOrigin = selectedAccount.requireAccountIdKeyIn(chain)
|
||||
val formattedCall = multisigCallFormatter.formatPreview(call, initialOrigin, chain)
|
||||
|
||||
return PendingSignatureModel(
|
||||
id = operationId,
|
||||
chain = mapChainToUi(chain),
|
||||
title = formattedCall.title,
|
||||
subtitle = formattedCall.subtitle,
|
||||
primaryValue = formattedCall.primaryValue,
|
||||
progress = resourceManager.getString(R.string.multisig_operations_progress, approvals.size.format(), threshold.format())
|
||||
)
|
||||
}
|
||||
|
||||
val pezkuwiDashboardFlow = selectedMetaAccount
|
||||
.combine(dashboardRefreshSignal) { account, _ -> account }
|
||||
.mapLatest { metaAccount ->
|
||||
|
||||
-3
@@ -13,7 +13,6 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule
|
||||
import io.novafoundation.nova.common.domain.usecase.MaskingModeUseCase
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.MultisigPendingOperationsService
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.callFormatting.MultisigCallFormatter
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepository
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_assets.data.repository.PezkuwiDashboardRepository
|
||||
@@ -123,7 +122,6 @@ class BalanceListModule {
|
||||
amountFormatter: AmountFormatter,
|
||||
buySellSelectorMixinFactory: BuySellSelectorMixinFactory,
|
||||
multisigPendingOperationsService: MultisigPendingOperationsService,
|
||||
multisigCallFormatter: MultisigCallFormatter,
|
||||
novaCardRestrictionCheckMixin: NovaCardRestrictionCheckMixin,
|
||||
maskableValueFormatterProvider: MaskableValueFormatterProvider,
|
||||
maskingModeUseCase: MaskingModeUseCase,
|
||||
@@ -150,7 +148,6 @@ class BalanceListModule {
|
||||
maskableValueFormatterProvider = maskableValueFormatterProvider,
|
||||
buySellSelectorMixinFactory = buySellSelectorMixinFactory,
|
||||
multisigPendingOperationsService = multisigPendingOperationsService,
|
||||
multisigCallFormatter = multisigCallFormatter,
|
||||
novaCardRestrictionCheckMixin = novaCardRestrictionCheckMixin,
|
||||
maskingModeUseCase = maskingModeUseCase,
|
||||
fiatFormatter = fiatFormatter,
|
||||
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package io.novafoundation.nova.feature_assets.presentation.balance.list.view
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.ImageLoader
|
||||
import io.novafoundation.nova.common.list.SingleItemAdapter
|
||||
import io.novafoundation.nova.common.utils.inflater
|
||||
import io.novafoundation.nova.common.utils.recyclerView.WithViewType
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon
|
||||
import io.novafoundation.nova.feature_assets.R
|
||||
import io.novafoundation.nova.feature_assets.databinding.ItemPendingSignatureRowBinding
|
||||
import io.novafoundation.nova.feature_assets.databinding.ItemPendingSignaturesCardBinding
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.model.PendingSignatureModel
|
||||
|
||||
class PendingSignaturesAdapter(
|
||||
private val imageLoader: ImageLoader,
|
||||
private val handler: Handler
|
||||
) : SingleItemAdapter<PendingSignaturesHolder>(isShownByDefault = false) {
|
||||
|
||||
interface Handler {
|
||||
fun onSignClicked(model: PendingSignatureModel)
|
||||
}
|
||||
|
||||
private var models: List<PendingSignatureModel> = emptyList()
|
||||
|
||||
fun setModels(models: List<PendingSignatureModel>) {
|
||||
this.models = models
|
||||
notifyChangedIfShown()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PendingSignaturesHolder {
|
||||
val binding = ItemPendingSignaturesCardBinding.inflate(parent.inflater(), parent, false)
|
||||
return PendingSignaturesHolder(binding, imageLoader, handler)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PendingSignaturesHolder, position: Int) {
|
||||
holder.bind(models)
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return PendingSignaturesHolder.viewType
|
||||
}
|
||||
}
|
||||
|
||||
class PendingSignaturesHolder(
|
||||
private val binder: ItemPendingSignaturesCardBinding,
|
||||
private val imageLoader: ImageLoader,
|
||||
private val handler: PendingSignaturesAdapter.Handler
|
||||
) : RecyclerView.ViewHolder(binder.root) {
|
||||
|
||||
companion object : WithViewType {
|
||||
override val viewType: Int = R.layout.item_pending_signatures_card
|
||||
}
|
||||
|
||||
fun bind(models: List<PendingSignatureModel>) {
|
||||
val container = binder.pendingSignaturesRowsContainer
|
||||
container.removeAllViews()
|
||||
|
||||
models.forEach { model ->
|
||||
val rowBinding = ItemPendingSignatureRowBinding.inflate(container.inflater(), container, false)
|
||||
|
||||
rowBinding.pendingSignatureChainIcon.loadChainIcon(model.chain.icon, imageLoader)
|
||||
// primaryValue (e.g. "100K USDT") is the amount - the whole point of this card - so it
|
||||
// takes the prominent title line; the call's own title/action name ("Transfer") isn't
|
||||
// shown at all here, only the destination (subtitle) is, to keep the row to two lines.
|
||||
rowBinding.pendingSignatureTitle.text = model.primaryValue ?: model.title
|
||||
rowBinding.pendingSignatureSubtitle.text = listOfNotNull(model.subtitle, model.chain.name, model.progress)
|
||||
.joinToString(separator = " • ")
|
||||
rowBinding.pendingSignatureSignButton.setOnClickListener { handler.onSignClicked(model) }
|
||||
|
||||
container.addView(rowBinding.root)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -3,19 +3,27 @@ package io.novafoundation.nova.feature_assets.presentation.bridge
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import coil.ImageLoader
|
||||
import io.novafoundation.nova.common.base.BaseFragment
|
||||
import io.novafoundation.nova.common.di.FeatureUtils
|
||||
import io.novafoundation.nova.common.utils.inflater
|
||||
import io.novafoundation.nova.common.utils.setVisible
|
||||
import io.novafoundation.nova.common.view.AlertView
|
||||
import io.novafoundation.nova.common.view.setState
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.chain.loadChainIcon
|
||||
import io.novafoundation.nova.feature_assets.R
|
||||
import io.novafoundation.nova.feature_assets.databinding.FragmentBridgeBinding
|
||||
import io.novafoundation.nova.feature_assets.databinding.ItemPendingSignatureRowBinding
|
||||
import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi
|
||||
import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.mixin.amountChooser.MaxActionAvailability
|
||||
import javax.inject.Inject
|
||||
|
||||
class BridgeFragment : BaseFragment<BridgeViewModel, FragmentBridgeBinding>() {
|
||||
|
||||
@Inject
|
||||
lateinit var imageLoader: ImageLoader
|
||||
|
||||
override fun createBinding() = FragmentBridgeBinding.inflate(layoutInflater)
|
||||
|
||||
override fun initViews() {
|
||||
@@ -196,6 +204,34 @@ class BridgeFragment : BaseFragment<BridgeViewModel, FragmentBridgeBinding>() {
|
||||
viewModel.fillAmountEvent.observeEvent { amount ->
|
||||
binder.bridgeFromCard.amountInput.setText(amount)
|
||||
}
|
||||
|
||||
viewModel.pendingSignatures.observe { models ->
|
||||
bindPendingSignatures(models)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindPendingSignatures(models: List<PendingSignatureModel>) {
|
||||
val visibility = if (models.isEmpty()) View.GONE else View.VISIBLE
|
||||
binder.bridgePendingSignaturesTitle.visibility = visibility
|
||||
binder.bridgePendingSignaturesContainer.visibility = visibility
|
||||
|
||||
val container = binder.bridgePendingSignaturesContainer
|
||||
container.removeAllViews()
|
||||
|
||||
models.forEach { model ->
|
||||
val rowBinding = ItemPendingSignatureRowBinding.inflate(container.inflater(), container, false)
|
||||
|
||||
rowBinding.pendingSignatureChainIcon.loadChainIcon(model.chain.icon, imageLoader)
|
||||
// primaryValue (e.g. "100K USDT") is the amount - the whole point of this row - so it
|
||||
// takes the prominent title line; the call's own title/action name ("Transfer") isn't
|
||||
// shown at all here, only the destination (subtitle) is, to keep the row to two lines.
|
||||
rowBinding.pendingSignatureTitle.text = model.primaryValue ?: model.title
|
||||
rowBinding.pendingSignatureSubtitle.text = listOfNotNull(model.subtitle, model.chain.name, model.progress)
|
||||
.joinToString(separator = " • ")
|
||||
rowBinding.pendingSignatureSignButton.setOnClickListener { viewModel.pendingSignatureSignClicked(model) }
|
||||
|
||||
container.addView(rowBinding.root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+58
@@ -6,8 +6,17 @@ import io.novafoundation.nova.common.base.BaseViewModel
|
||||
import io.novafoundation.nova.common.presentation.AssetIconProvider
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.common.utils.Event
|
||||
import io.novafoundation.nova.common.utils.formatting.format
|
||||
import io.novafoundation.nova.common.utils.images.Icon
|
||||
import io.novafoundation.nova.common.view.ButtonState
|
||||
import io.novafoundation.nova.feature_account_api.data.mappers.mapChainToUi
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.MultisigPendingOperationsService
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.MultisigAction
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.PendingMultisigOperation
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.userAction
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.requireAccountIdKeyIn
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.chain.getAssetIconOrFallback
|
||||
import io.novafoundation.nova.feature_assets.R
|
||||
import io.novafoundation.nova.feature_assets.domain.WalletInteractor
|
||||
@@ -16,12 +25,17 @@ import io.novafoundation.nova.feature_assets.domain.bridge.multisig.BridgeMultis
|
||||
import io.novafoundation.nova.feature_assets.domain.bridge.multisig.BridgeSignerState
|
||||
import io.novafoundation.nova.feature_assets.presentation.AssetsRouter
|
||||
import io.novafoundation.nova.feature_assets.presentation.bridge.execution.BridgeExecutionPayload
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.callFormatting.MultisigCallFormatter
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.common.MultisigOperationPayload
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.common.fromOperationId
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.details.general.MultisigOperationDetailsPayload
|
||||
import io.novafoundation.nova.runtime.ext.ChainGeneses
|
||||
import io.novafoundation.nova.runtime.ext.addressOf
|
||||
import io.novafoundation.nova.runtime.ext.displayNameWithAssetStandard
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novasama.substrate_sdk_android.ss58.SS58Encoder.toAccountId
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
@@ -48,6 +62,9 @@ class BridgeViewModel(
|
||||
private val assetIconProvider: AssetIconProvider,
|
||||
private val walletInteractor: WalletInteractor,
|
||||
private val bridgeMultisigInteractor: BridgeMultisigInteractor,
|
||||
private val multisigPendingOperationsService: MultisigPendingOperationsService,
|
||||
private val multisigCallFormatter: MultisigCallFormatter,
|
||||
private val selectedAccountUseCase: SelectedAccountUseCase,
|
||||
) : BaseViewModel() {
|
||||
|
||||
companion object {
|
||||
@@ -130,6 +147,15 @@ class BridgeViewModel(
|
||||
private val _polkadotSignButtonLabel = MutableLiveData("")
|
||||
val polkadotSignButtonLabel: LiveData<String> = _polkadotSignButtonLabel
|
||||
|
||||
/** Multisig operations (any of them - not just bridge swaps, since a signatory of this bridge
|
||||
* account may also be a signatory of other multisig accounts) still awaiting this wallet's
|
||||
* own approval - shown below the renewal sign buttons above so a signatory doesn't have to
|
||||
* separately navigate to the pending-operations list to find and sign a swap someone else
|
||||
* submitted (see the "Sign" buttons above, which renew this wallet's own on-chain allowance -
|
||||
* this is a different, complementary concern: approving *other people's* pending calls). */
|
||||
private val _pendingSignatures = MutableLiveData<List<PendingSignatureModel>>(emptyList())
|
||||
val pendingSignatures: LiveData<List<PendingSignatureModel>> = _pendingSignatures
|
||||
|
||||
private val _fromCard = MutableLiveData<BridgeAssetCardUi>()
|
||||
val fromCard: LiveData<BridgeAssetCardUi> = _fromCard
|
||||
|
||||
@@ -452,6 +478,38 @@ class BridgeViewModel(
|
||||
fun refreshBridgeStatus() {
|
||||
fetchReserveStatus()
|
||||
refreshSignerState()
|
||||
refreshPendingSignatures()
|
||||
}
|
||||
|
||||
fun refreshPendingSignatures() {
|
||||
launch {
|
||||
val account = selectedAccountUseCase.getSelectedMetaAccount()
|
||||
|
||||
val models = multisigPendingOperationsService.pendingOperations().first()
|
||||
.filter { it.userAction() is MultisigAction.CanApprove }
|
||||
.map { it.toPendingSignatureUi(account) }
|
||||
|
||||
_pendingSignatures.postValue(models)
|
||||
}
|
||||
}
|
||||
|
||||
fun pendingSignatureSignClicked(model: PendingSignatureModel) {
|
||||
val operationPayload = MultisigOperationPayload.fromOperationId(model.id)
|
||||
router.openMultisigOperationDetails(MultisigOperationDetailsPayload(operationPayload))
|
||||
}
|
||||
|
||||
private suspend fun PendingMultisigOperation.toPendingSignatureUi(selectedAccount: MetaAccount): PendingSignatureModel {
|
||||
val initialOrigin = selectedAccount.requireAccountIdKeyIn(chain)
|
||||
val formattedCall = multisigCallFormatter.formatPreview(call, initialOrigin, chain)
|
||||
|
||||
return PendingSignatureModel(
|
||||
id = operationId,
|
||||
chain = mapChainToUi(chain),
|
||||
title = formattedCall.title,
|
||||
subtitle = formattedCall.subtitle,
|
||||
primaryValue = formattedCall.primaryValue,
|
||||
progress = resourceManager.getString(R.string.multisig_operations_progress, approvals.size.format(), threshold.format())
|
||||
)
|
||||
}
|
||||
|
||||
fun refreshSignerState() {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.novafoundation.nova.feature_assets.presentation.balance.list.model
|
||||
package io.novafoundation.nova.feature_assets.presentation.bridge
|
||||
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.model.PendingMultisigOperationId
|
||||
import io.novafoundation.nova.feature_account_api.presenatation.chain.ChainUi
|
||||
+8
@@ -11,12 +11,14 @@ import io.novafoundation.nova.common.di.viewmodel.ViewModelModule
|
||||
import io.novafoundation.nova.common.presentation.AssetIconProvider
|
||||
import io.novafoundation.nova.common.resources.ResourceManager
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_account_api.data.multisig.MultisigPendingOperationsService
|
||||
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
|
||||
import io.novafoundation.nova.feature_assets.domain.WalletInteractor
|
||||
import io.novafoundation.nova.feature_assets.domain.bridge.multisig.BridgeMultisigInteractor
|
||||
import io.novafoundation.nova.feature_assets.domain.bridge.multisig.RealBridgeMultisigInteractor
|
||||
import io.novafoundation.nova.feature_assets.presentation.AssetsRouter
|
||||
import io.novafoundation.nova.feature_assets.presentation.bridge.BridgeViewModel
|
||||
import io.novafoundation.nova.feature_multisig_operations.presentation.callFormatting.MultisigCallFormatter
|
||||
import io.novafoundation.nova.runtime.di.REMOTE_STORAGE_SOURCE
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.storage.source.StorageDataSource
|
||||
@@ -45,6 +47,9 @@ class BridgeModule {
|
||||
assetIconProvider: AssetIconProvider,
|
||||
walletInteractor: WalletInteractor,
|
||||
bridgeMultisigInteractor: BridgeMultisigInteractor,
|
||||
multisigPendingOperationsService: MultisigPendingOperationsService,
|
||||
multisigCallFormatter: MultisigCallFormatter,
|
||||
selectedAccountUseCase: SelectedAccountUseCase,
|
||||
): ViewModel {
|
||||
return BridgeViewModel(
|
||||
router,
|
||||
@@ -53,6 +58,9 @@ class BridgeModule {
|
||||
assetIconProvider,
|
||||
walletInteractor,
|
||||
bridgeMultisigInteractor,
|
||||
multisigPendingOperationsService,
|
||||
multisigCallFormatter,
|
||||
selectedAccountUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -214,6 +214,26 @@
|
||||
android:text="@string/bridge_sign_button"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Pending multisig operations awaiting this signatory's own approval (someone
|
||||
else's swap, not this wallet's own renewal above) - one row per operation,
|
||||
populated dynamically, see BridgeViewModel.pendingSignatures. -->
|
||||
<TextView
|
||||
android:id="@+id/bridgePendingSignaturesTitle"
|
||||
style="@style/TextAppearance.NovaFoundation.SemiBold.Caption1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/pending_signatures_title"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bridgePendingSignaturesContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeWidth="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_pezkuwi_dashboard"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="12dp">
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.NovaFoundation.SemiBold.Caption1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/pending_signatures_title"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/pendingSignaturesRowsContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
Reference in New Issue
Block a user