diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index 47386504..8854432a 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -375,10 +375,11 @@ Signing failed, tap to retry Bridge complete — funds delivered - Still processing - this can take longer if it needs manual multisig review. Check back in a few minutes. + Still processing - this can take longer if it needs manual multisig review. Your funds are safe and recorded on-chain. Check back in a few minutes, or reach the signatories at t.me/pezkuwidestek. Submitting transfer… Waiting for confirmation on %s… + Do not close the app! Buy/Sell diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionFragment.kt index 9b0d0b62..becccf48 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionFragment.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionFragment.kt @@ -28,6 +28,9 @@ class BridgeExecutionFragment : BaseFragment binder.bridgeExecutionDoneButton.visibility = if (visible) View.VISIBLE else View.GONE + // "Do not close the app!" only makes sense while something is genuinely still in + // flight - doneButtonVisible becomes true exactly once the operation has resolved + // (success, pending review, or failure), so its inverse is the same signal without a + // separate LiveData to keep in sync. + binder.bridgeExecutionDoNotClose.visibility = if (visible) View.GONE else View.VISIBLE + } + + viewModel.fromCard.observe { model -> + binder.bridgeExecutionFromCard.setModel(model) + } + + viewModel.toCard.observe { model -> + binder.bridgeExecutionToCard.setModel(model) + } + + viewModel.fromAmountText.observe { text -> + binder.bridgeExecutionFromCard.setAmountText(text) + } + + viewModel.toAmountText.observe { text -> + binder.bridgeExecutionToCard.setAmountText(text) } // Single source of truth for the alert banner - only OriginFailed (error) and diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionViewModel.kt index d3b1bdab..6ff98740 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionViewModel.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/BridgeExecutionViewModel.kt @@ -4,23 +4,29 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope 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.view.ExecutionTimerView import io.novafoundation.nova.feature_account_api.data.fee.FeePaymentCurrency import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase +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 import io.novafoundation.nova.feature_assets.domain.send.SendInteractor import io.novafoundation.nova.feature_assets.presentation.AssetsRouter +import io.novafoundation.nova.feature_assets.presentation.bridge.BridgeAssetCardUi import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.tranfers.WeightedAssetTransfer import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.tranfers.buildAssetTransfer import io.novafoundation.nova.feature_wallet_api.domain.SendUseCase +import io.novafoundation.nova.runtime.ext.displayNameWithAssetStandard import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry import io.novafoundation.nova.runtime.multiNetwork.ChainWithAsset +import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull import java.math.BigDecimal +import java.math.RoundingMode import kotlin.time.Duration.Companion.seconds /** @@ -35,6 +41,7 @@ class BridgeExecutionViewModel( private val payload: BridgeExecutionPayload, private val resourceManager: ResourceManager, private val chainRegistry: ChainRegistry, + private val assetIconProvider: AssetIconProvider, private val walletInteractor: WalletInteractor, private val sendInteractor: SendInteractor, private val sendUseCase: SendUseCase, @@ -66,7 +73,22 @@ class BridgeExecutionViewModel( private val _doneButtonVisible = MutableLiveData(false) val doneButtonVisible: LiveData = _doneButtonVisible + private val _fromCard = MutableLiveData() + val fromCard: LiveData = _fromCard + + private val _toCard = MutableLiveData() + val toCard: LiveData = _toCard + + private val _fromAmountText = MutableLiveData("") + val fromAmountText: LiveData = _fromAmountText + + private val _toAmountText = MutableLiveData("") + val toAmountText: LiveData = _toAmountText + init { + launch { + loadCards() + } launch { submit() } @@ -76,6 +98,30 @@ class BridgeExecutionViewModel( router.back() } + private suspend fun loadCards() { + val originChain = chainRegistry.getChain(payload.originChainId) + val destChain = chainRegistry.getChain(payload.destChainId) + + _fromCard.postValue(cardUiFor(originChain, payload.originAssetId)) + _toCard.postValue(cardUiFor(destChain, payload.destAssetId)) + + _fromAmountText.postValue(BigDecimal.valueOf(payload.amount).stripTrailingZeros().toPlainString()) + + val netOutput = payload.amount * (1 - FEE_PERCENT) + _toAmountText.postValue(BigDecimal(netOutput).setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString()) + } + + private suspend fun cardUiFor(chain: Chain, assetId: Int): BridgeAssetCardUi { + val asset = chain.assetsById.getValue(assetId) + + return BridgeAssetCardUi( + assetIcon = assetIconProvider.getAssetIconOrFallback(asset), + chainIconUrl = chain.icon, + symbol = asset.symbol.value, + chainName = chain.displayNameWithAssetStandard() + ) + } + private suspend fun submit() { _state.postValue(BridgeExecutionState.SubmittingOrigin) _label.postValue(resourceManager.getString(R.string.bridge_execution_submitting_label)) diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/di/BridgeExecutionModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/di/BridgeExecutionModule.kt index cdac55e0..f99dec80 100644 --- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/di/BridgeExecutionModule.kt +++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/bridge/execution/di/BridgeExecutionModule.kt @@ -8,6 +8,7 @@ import dagger.Provides import dagger.multibindings.IntoMap import io.novafoundation.nova.common.di.viewmodel.ViewModelKey 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.domain.interfaces.SelectedAccountUseCase import io.novafoundation.nova.feature_assets.domain.WalletInteractor @@ -28,6 +29,7 @@ class BridgeExecutionModule { payload: BridgeExecutionPayload, resourceManager: ResourceManager, chainRegistry: ChainRegistry, + assetIconProvider: AssetIconProvider, walletInteractor: WalletInteractor, sendInteractor: SendInteractor, sendUseCase: SendUseCase, @@ -38,6 +40,7 @@ class BridgeExecutionModule { payload, resourceManager, chainRegistry, + assetIconProvider, walletInteractor, sendInteractor, sendUseCase, diff --git a/feature-assets/src/main/res/layout/fragment_bridge_execution.xml b/feature-assets/src/main/res/layout/fragment_bridge_execution.xml index fbf8ea54..1d925390 100644 --- a/feature-assets/src/main/res/layout/fragment_bridge_execution.xml +++ b/feature-assets/src/main/res/layout/fragment_bridge_execution.xml @@ -13,39 +13,88 @@ app:layout_constraintTop_toTopOf="parent" app:titleText="@string/bridge_title" /> - - + android:orientation="vertical" + android:padding="16dp"> - + + - + - + + + + + + + + + + + + + + +