Redesign Bridge screen UI to match Swap's modern card layout

Replaces the segmented pair/direction buttons and plain-text amount
sections with token-icon cards (BridgeAssetInputView), a one-tap flip
button, and a bottom-sheet pair picker (BridgePairListBottomSheet).
BridgeViewModel gains only additive presentation data (fromCard/toCard/
pairOptions, derived from the existing pair/direction state and the
same chainId/assetId mapping swapClicked() already used) - all bridge
business logic (rate, fee, minimum, liquidity warnings, submission)
is unchanged.
This commit is contained in:
2026-07-13 09:28:30 -07:00
parent 4d1fb0256f
commit 398f2fc996
8 changed files with 416 additions and 287 deletions
+2
View File
@@ -355,6 +355,8 @@
<!-- Bridge Screen -->
<string name="bridge_title">DOT ↔ HEZ Bridge</string>
<string name="bridge_pair_dot_hez">HEZ ⇄ DOT</string>
<string name="bridge_pair_usdt">USDT ⇄ USDT.p</string>
<string name="bridge_you_send">You send</string>
<string name="bridge_you_receive">You receive (estimated)</string>
<string name="bridge_exchange_rate">Exchange rate</string>
@@ -2,11 +2,11 @@ package io.novafoundation.nova.feature_assets.presentation.bridge
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import io.novafoundation.nova.common.base.BaseFragment
import io.novafoundation.nova.common.di.FeatureUtils
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_assets.R
import io.novafoundation.nova.feature_assets.databinding.FragmentBridgeBinding
import io.novafoundation.nova.feature_assets.di.AssetsFeatureApi
import io.novafoundation.nova.feature_assets.di.AssetsFeatureComponent
@@ -18,26 +18,29 @@ class BridgeFragment : BaseFragment<BridgeViewModel, FragmentBridgeBinding>() {
override fun initViews() {
binder.bridgeToolbar.setHomeButtonListener { viewModel.backClicked() }
// Pair selector
binder.bridgePairDotHez.setOnClickListener {
viewModel.setPair(BridgePair.DOT_HEZ)
binder.bridgeToCard.setEditable(false)
// Tapping the "from" card opens the pair picker - replaces the old segmented pair buttons
binder.bridgeFromCard.setCardClickListener {
val options = viewModel.pairOptions.value.orEmpty()
if (options.isNotEmpty()) {
BridgePairListBottomSheet(requireContext(), options) { selected ->
viewModel.setPair(selected.pair)
}.show()
}
}
binder.bridgePairUsdt.setOnClickListener {
viewModel.setPair(BridgePair.USDT)
}
// Direction toggle
binder.bridgeDirectionLeft.setOnClickListener {
viewModel.setDirectionLeft()
}
binder.bridgeDirectionRight.setOnClickListener {
viewModel.setDirectionRight()
// One-tap direction flip - replaces the old segmented direction buttons
binder.bridgeFlipButton.setOnClickListener {
when (viewModel.direction.value) {
BridgeDirection.DOT_TO_HEZ, BridgeDirection.USDT_TO_WUSDT -> viewModel.setDirectionRight()
BridgeDirection.HEZ_TO_DOT, BridgeDirection.WUSDT_TO_USDT -> viewModel.setDirectionLeft()
null -> Unit
}
}
// Amount input
binder.bridgeFromAmount.addTextChangedListener(object : TextWatcher {
binder.bridgeFromCard.amountInput.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
@@ -63,16 +66,16 @@ class BridgeFragment : BaseFragment<BridgeViewModel, FragmentBridgeBinding>() {
}
override fun subscribe(viewModel: BridgeViewModel) {
viewModel.pair.observe { pair ->
updatePairUI(pair)
viewModel.fromCard.observe { model ->
binder.bridgeFromCard.setModel(model)
}
viewModel.direction.observe { direction ->
updateDirectionUI(direction)
viewModel.toCard.observe { model ->
binder.bridgeToCard.setModel(model)
}
viewModel.outputAmount.observe { output ->
binder.bridgeToAmount.text = output
binder.bridgeToCard.setAmountText(output)
}
viewModel.exchangeRateText.observe { rate ->
@@ -88,80 +91,18 @@ class BridgeFragment : BaseFragment<BridgeViewModel, FragmentBridgeBinding>() {
}
viewModel.showWarning.observe { show ->
binder.bridgeHezToDotWarning.visibility = if (show) View.VISIBLE else View.GONE
binder.bridgeWarningAlert.setVisible(show)
}
viewModel.warningBlocked.observe { blocked ->
if (blocked) {
binder.bridgeHezToDotWarning.setBackgroundColor(resources.getColor(R.color.error_block_background, null))
} else {
binder.bridgeHezToDotWarning.setBackgroundColor(resources.getColor(R.color.warning_block_background, null))
}
binder.bridgeWarningAlert.setStylePreset(
if (blocked) AlertView.StylePreset.ERROR else AlertView.StylePreset.WARNING
)
}
viewModel.warningText.observe { text ->
if (text.isNotEmpty()) {
binder.bridgeHezToDotWarning.text = text
}
}
}
private fun updatePairUI(pair: BridgePair) {
when (pair) {
BridgePair.DOT_HEZ -> {
binder.bridgePairDotHez.setBackgroundResource(R.drawable.bg_button_primary)
binder.bridgePairDotHez.setTextColor(resources.getColor(R.color.text_primary, null))
binder.bridgePairUsdt.background = null
binder.bridgePairUsdt.setTextColor(resources.getColor(R.color.text_secondary, null))
}
BridgePair.USDT -> {
binder.bridgePairUsdt.setBackgroundResource(R.drawable.bg_button_primary)
binder.bridgePairUsdt.setTextColor(resources.getColor(R.color.text_primary, null))
binder.bridgePairDotHez.background = null
binder.bridgePairDotHez.setTextColor(resources.getColor(R.color.text_secondary, null))
}
}
}
private fun updateDirectionUI(direction: BridgeDirection) {
val isLeft = direction == BridgeDirection.DOT_TO_HEZ || direction == BridgeDirection.USDT_TO_WUSDT
if (isLeft) {
binder.bridgeDirectionLeft.setBackgroundResource(R.drawable.bg_button_primary)
binder.bridgeDirectionLeft.setTextColor(resources.getColor(R.color.text_primary, null))
binder.bridgeDirectionRight.background = null
binder.bridgeDirectionRight.setTextColor(resources.getColor(R.color.text_secondary, null))
} else {
binder.bridgeDirectionRight.setBackgroundResource(R.drawable.bg_button_primary)
binder.bridgeDirectionRight.setTextColor(resources.getColor(R.color.text_primary, null))
binder.bridgeDirectionLeft.background = null
binder.bridgeDirectionLeft.setTextColor(resources.getColor(R.color.text_secondary, null))
}
when (direction) {
BridgeDirection.DOT_TO_HEZ -> {
binder.bridgeDirectionLeft.text = "DOT → HEZ"
binder.bridgeDirectionRight.text = "HEZ → DOT"
binder.bridgeFromToken.text = "DOT"
binder.bridgeToToken.text = "HEZ"
}
BridgeDirection.HEZ_TO_DOT -> {
binder.bridgeDirectionLeft.text = "DOT → HEZ"
binder.bridgeDirectionRight.text = "HEZ → DOT"
binder.bridgeFromToken.text = "HEZ"
binder.bridgeToToken.text = "DOT"
}
BridgeDirection.USDT_TO_WUSDT -> {
binder.bridgeDirectionLeft.text = "USDT(Pol) → USDT(Pez)"
binder.bridgeDirectionRight.text = "USDT(Pez) → USDT(Pol)"
binder.bridgeFromToken.text = "USDT"
binder.bridgeToToken.text = "USDT"
}
BridgeDirection.WUSDT_TO_USDT -> {
binder.bridgeDirectionLeft.text = "USDT(Pol) → USDT(Pez)"
binder.bridgeDirectionRight.text = "USDT(Pez) → USDT(Pol)"
binder.bridgeFromToken.text = "USDT"
binder.bridgeToToken.text = "USDT"
binder.bridgeWarningAlert.setMessage(text)
}
}
}
@@ -0,0 +1,68 @@
package io.novafoundation.nova.feature_assets.presentation.bridge
import android.content.Context
import android.os.Bundle
import androidx.recyclerview.widget.DiffUtil
import coil.ImageLoader
import io.novafoundation.nova.common.di.FeatureUtils
import io.novafoundation.nova.common.utils.images.Icon
import io.novafoundation.nova.common.utils.images.setIconOrMakeGone
import io.novafoundation.nova.common.utils.inflater
import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.DynamicListBottomSheet
import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.DynamicListSheetAdapter
import io.novafoundation.nova.common.view.bottomSheet.list.dynamic.HolderCreator
import io.novafoundation.nova.feature_assets.R
import io.novafoundation.nova.feature_assets.databinding.ItemBridgePairListBinding
data class BridgePairUi(
val pair: BridgePair,
val icon: Icon,
val title: String
)
class BridgePairListBottomSheet(
context: Context,
data: List<BridgePairUi>,
onClicked: (BridgePairUi) -> Unit
) : DynamicListBottomSheet<BridgePairUi>(
context,
Payload(data),
BridgePairDiffCallback,
onClicked = { _, item -> onClicked(item) }
) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTitle(R.string.bridge_title)
}
override fun holderCreator(): HolderCreator<BridgePairUi> = {
BridgePairListHolder(ItemBridgePairListBinding.inflate(it.inflater(), it, false))
}
}
class BridgePairListHolder(
private val binder: ItemBridgePairListBinding
) : DynamicListSheetAdapter.Holder<BridgePairUi>(binder.root) {
private val imageLoader: ImageLoader by lazy(LazyThreadSafetyMode.NONE) {
FeatureUtils.getCommonApi(binder.root.context).imageLoader()
}
override fun bind(item: BridgePairUi, isSelected: Boolean, handler: DynamicListSheetAdapter.Handler<BridgePairUi>) {
binder.itemBridgePairIcon.setIconOrMakeGone(item.icon, imageLoader)
binder.itemBridgePairTitle.text = item.title
binder.root.setOnClickListener { handler.itemClicked(item) }
}
}
private object BridgePairDiffCallback : DiffUtil.ItemCallback<BridgePairUi>() {
override fun areItemsTheSame(oldItem: BridgePairUi, newItem: BridgePairUi): Boolean {
return oldItem.pair == newItem.pair
}
override fun areContentsTheSame(oldItem: BridgePairUi, newItem: BridgePairUi): Boolean {
return true
}
}
@@ -4,7 +4,9 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import io.novafoundation.nova.common.base.BaseViewModel
import io.novafoundation.nova.common.resources.ResourceManager
import io.novafoundation.nova.common.utils.images.Icon
import io.novafoundation.nova.common.view.ButtonState
import io.novafoundation.nova.feature_account_api.presenatation.chain.asIconOrFallback
import io.novafoundation.nova.feature_assets.R
import io.novafoundation.nova.feature_assets.presentation.AssetsRouter
import io.novafoundation.nova.feature_assets.presentation.send.amount.SendPayload
@@ -12,6 +14,7 @@ import io.novafoundation.nova.feature_wallet_api.presentation.model.AssetPayload
import io.novafoundation.nova.runtime.ext.ChainGeneses
import io.novafoundation.nova.runtime.ext.addressOf
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
import io.novasama.substrate_sdk_android.ss58.SS58Encoder.toAccountId
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -76,6 +79,15 @@ class BridgeViewModel(
private val _warningText = MutableLiveData<String>()
val warningText: LiveData<String> = _warningText
private val _fromCard = MutableLiveData<BridgeAssetCardUi>()
val fromCard: LiveData<BridgeAssetCardUi> = _fromCard
private val _toCard = MutableLiveData<BridgeAssetCardUi>()
val toCard: LiveData<BridgeAssetCardUi> = _toCard
private val _pairOptions = MutableLiveData<List<BridgePairUi>>(emptyList())
val pairOptions: LiveData<List<BridgePairUi>> = _pairOptions
private var currentAmount: Double = 0.0
private var dotToHezRate: Double = FALLBACK_RATE
private var isHezToDotActive: Boolean = false
@@ -84,6 +96,8 @@ class BridgeViewModel(
init {
fetchExchangeRate()
fetchBridgeStatus()
updateCards()
loadPairOptions()
}
fun setPair(newPair: BridgePair) {
@@ -97,6 +111,7 @@ class BridgeViewModel(
updateUI()
calculateOutput()
updateWarningState()
updateCards()
}
}
@@ -111,6 +126,7 @@ class BridgeViewModel(
updateUI()
calculateOutput()
updateWarningState()
updateCards()
}
}
@@ -125,6 +141,7 @@ class BridgeViewModel(
updateUI()
calculateOutput()
updateWarningState()
updateCards()
}
}
@@ -322,4 +339,65 @@ class BridgeViewModel(
fun refreshBridgeStatus() {
fetchBridgeStatus()
}
private fun updateCards() {
val dir = _direction.value ?: return
// Same chainId/assetId mapping already used by swapClicked() to resolve the origin side -
// mirrored here (plus its destination counterpart) purely to display logos/names, no new business rule.
val originChainId = when (dir) {
BridgeDirection.DOT_TO_HEZ, BridgeDirection.USDT_TO_WUSDT -> POLKADOT_ASSET_HUB_ID
BridgeDirection.HEZ_TO_DOT, BridgeDirection.WUSDT_TO_USDT -> PEZKUWI_ASSET_HUB_ID
}
val destChainId = when (dir) {
BridgeDirection.DOT_TO_HEZ, BridgeDirection.USDT_TO_WUSDT -> PEZKUWI_ASSET_HUB_ID
BridgeDirection.HEZ_TO_DOT, BridgeDirection.WUSDT_TO_USDT -> POLKADOT_ASSET_HUB_ID
}
val originAssetId = when (dir) {
BridgeDirection.DOT_TO_HEZ, BridgeDirection.HEZ_TO_DOT -> UTILITY_ASSET_ID
BridgeDirection.USDT_TO_WUSDT -> POLKADOT_USDT_ASSET_ID
BridgeDirection.WUSDT_TO_USDT -> PEZKUWI_USDT_ASSET_ID
}
val destAssetId = when (dir) {
BridgeDirection.DOT_TO_HEZ, BridgeDirection.HEZ_TO_DOT -> UTILITY_ASSET_ID
BridgeDirection.USDT_TO_WUSDT -> PEZKUWI_USDT_ASSET_ID
BridgeDirection.WUSDT_TO_USDT -> POLKADOT_USDT_ASSET_ID
}
launch {
_fromCard.value = cardUiFor(originChainId, originAssetId)
_toCard.value = cardUiFor(destChainId, destAssetId)
}
}
private fun loadPairOptions() {
launch {
val dotHezIcon = cardUiFor(POLKADOT_ASSET_HUB_ID, UTILITY_ASSET_ID).assetIcon
val usdtIcon = cardUiFor(POLKADOT_ASSET_HUB_ID, POLKADOT_USDT_ASSET_ID).assetIcon
_pairOptions.value = listOf(
BridgePairUi(BridgePair.DOT_HEZ, dotHezIcon, resourceManager.getString(R.string.bridge_pair_dot_hez)),
BridgePairUi(BridgePair.USDT, usdtIcon, resourceManager.getString(R.string.bridge_pair_usdt))
)
}
}
private suspend fun cardUiFor(chainId: String, assetId: Int): BridgeAssetCardUi {
val chain = chainRegistry.getChain(chainId)
val asset = chain.assetsById.getValue(assetId)
return BridgeAssetCardUi(
assetIcon = asset.icon.asIconOrFallback(),
chainIconUrl = chain.icon,
symbol = asset.symbol.value,
chainName = chain.name
)
}
}
data class BridgeAssetCardUi(
val assetIcon: Icon,
val chainIconUrl: String?,
val symbol: String,
val chainName: String
)
@@ -0,0 +1,63 @@
package io.novafoundation.nova.feature_assets.presentation.bridge.view
import android.content.Context
import android.util.AttributeSet
import android.widget.EditText
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import coil.ImageLoader
import io.novafoundation.nova.common.di.FeatureUtils
import io.novafoundation.nova.common.utils.WithContextExtensions
import io.novafoundation.nova.common.utils.images.asUrlIcon
import io.novafoundation.nova.common.utils.images.setIconOrMakeGone
import io.novafoundation.nova.common.utils.inflater
import io.novafoundation.nova.common.view.shape.getInputBackground
import io.novafoundation.nova.feature_account_api.presenatation.chain.setTokenIcon
import io.novafoundation.nova.feature_assets.databinding.ViewBridgeAssetInputBinding
import io.novafoundation.nova.feature_assets.presentation.bridge.BridgeAssetCardUi
class BridgeAssetInputView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr),
WithContextExtensions by WithContextExtensions(context) {
private val binder = ViewBridgeAssetInputBinding.inflate(inflater(), this)
val amountInput: EditText
get() = binder.bridgeAssetInputField
private val imageLoader: ImageLoader by lazy(LazyThreadSafetyMode.NONE) {
FeatureUtils.getCommonApi(context).imageLoader()
}
init {
binder.bridgeAssetInputContainer.background = context.getInputBackground()
}
fun setCardClickListener(listener: OnClickListener) {
binder.bridgeAssetInputContainer.setOnClickListener(listener)
binder.bridgeAssetInputChevron.isVisible = true
}
fun setEditable(editable: Boolean) {
amountInput.isFocusable = editable
amountInput.isFocusableInTouchMode = editable
amountInput.isClickable = editable
amountInput.isCursorVisible = editable
}
fun setAmountText(text: CharSequence) {
if (amountInput.text?.toString() != text.toString()) {
amountInput.setText(text)
}
}
fun setModel(model: BridgeAssetCardUi) {
binder.bridgeAssetInputImage.setTokenIcon(model.assetIcon, imageLoader)
binder.bridgeAssetInputToken.text = model.symbol
binder.bridgeAssetInputSubtitle.text = model.chainName
binder.bridgeAssetInputSubtitleImage.setIconOrMakeGone(model.chainIconUrl?.asUrlIcon(), imageLoader)
}
}
@@ -25,212 +25,51 @@
android:orientation="vertical"
android:padding="16dp">
<!-- Pair Selector -->
<LinearLayout
<TextView
android:id="@+id/bridgeFromLabel"
style="@style/TextAppearance.NovaFoundation.Regular.Footnote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bridge_you_send"
android:textColor="@color/text_secondary" />
<io.novafoundation.nova.feature_assets.presentation.bridge.view.BridgeAssetInputView
android:id="@+id/bridgeFromCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_primary_list_item"
android:orientation="horizontal"
android:padding="4dp">
android:layout_marginTop="8dp" />
<TextView
android:id="@+id/bridgePairDotHez"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_button_primary"
android:gravity="center"
android:padding="10dp"
android:text="DOT / HEZ"
android:textColor="@color/text_primary"
android:textSize="13sp"
android:textStyle="bold" />
<TextView
android:id="@+id/bridgePairUsdt"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:text="USDT"
android:textColor="@color/text_secondary"
android:textSize="13sp" />
</LinearLayout>
<!-- Direction Toggle -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="@drawable/bg_primary_list_item"
android:orientation="horizontal"
android:padding="4dp">
<TextView
android:id="@+id/bridgeDirectionLeft"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_button_primary"
android:gravity="center"
android:padding="12dp"
android:text="DOT → HEZ"
android:textColor="@color/text_primary"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/bridgeDirectionRight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="12dp"
android:text="HEZ → DOT"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
</LinearLayout>
<!-- From Section -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:cardBackgroundColor="@color/block_background"
app:cardCornerRadius="12dp"
app:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/bridgeFromLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bridge_you_send"
android:textColor="@color/text_secondary"
android:textSize="12sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="@+id/bridgeFromAmount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@null"
android:hint="0.0"
android:inputType="numberDecimal"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="32sp"
android:textStyle="bold" />
<TextView
android:id="@+id/bridgeFromToken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOT"
android:textColor="@color/text_primary"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/bridgeFromBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/text_secondary"
android:textSize="12sp"
tools:text="Balance: 10.5 DOT" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Swap Icon -->
<ImageView
android:id="@+id/bridgeFlipButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_marginVertical="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
android:src="@drawable/ic_bridge"
app:tint="@color/icon_secondary" />
android:scaleType="centerInside"
android:src="@drawable/ic_flip_swap" />
<!-- To Section -->
<com.google.android.material.card.MaterialCardView
<TextView
android:id="@+id/bridgeToLabel"
style="@style/TextAppearance.NovaFoundation.Regular.Footnote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/bridge_you_receive"
android:textColor="@color/text_secondary" />
<io.novafoundation.nova.feature_assets.presentation.bridge.view.BridgeAssetInputView
android:id="@+id/bridgeToCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:cardBackgroundColor="@color/block_background"
app:cardCornerRadius="12dp"
app:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/bridgeToLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bridge_you_receive"
android:textColor="@color/text_secondary"
android:textSize="12sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/bridgeToAmount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0"
android:textColor="@color/text_primary"
android:textSize="32sp"
android:textStyle="bold" />
<TextView
android:id="@+id/bridgeToToken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HEZ"
android:textColor="@color/text_primary"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
android:layout_marginTop="8dp" />
<!-- Rate Info -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardBackgroundColor="@color/block_background"
app:cardCornerRadius="12dp"
app:cardElevation="0dp">
@@ -317,18 +156,14 @@
</com.google.android.material.card.MaterialCardView>
<!-- Warning for HEZ to DOT -->
<TextView
android:id="@+id/bridgeHezToDotWarning"
<!-- Warning for HEZ to DOT / USDT liquidity -->
<io.novafoundation.nova.common.view.AlertView
android:id="@+id/bridgeWarningAlert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/bg_warning"
android:padding="12dp"
android:text="@string/bridge_hez_to_dot_note"
android:textColor="@color/text_warning"
android:textSize="12sp"
android:visibility="gone" />
android:visibility="gone"
app:alertMode="warning" />
</LinearLayout>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="16dp"
android:paddingVertical="12dp">
<ImageView
android:id="@+id/itemBridgePairIcon"
android:layout_width="32dp"
android:layout_height="32dp"
android:background="@drawable/bg_token_container"
android:scaleType="centerInside"
tools:src="@drawable/ic_pezkuwi_logo" />
<TextView
android:id="@+id/itemBridgePairTitle"
style="@style/TextAppearance.NovaFoundation.SemiBold.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:textColor="@color/text_primary"
tools:text="HEZ ⇄ DOT" />
</LinearLayout>
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bridgeAssetInputContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:background="@color/input_background">
<ImageView
android:id="@+id/bridgeAssetInputImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="12dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="@drawable/bg_token_container"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_token_dot_colored" />
<ImageView
android:id="@+id/bridgeAssetInputSubtitleImage"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginEnd="4dp"
app:layout_constraintBottom_toBottomOf="@+id/bridgeAssetInputSubtitle"
app:layout_constraintStart_toEndOf="@+id/bridgeAssetInputImageBarrier"
app:layout_constraintTop_toTopOf="@+id/bridgeAssetInputSubtitle"
tools:src="@drawable/ic_pezkuwi_logo" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bridgeAssetInputImageBarrier"
android:layout_width="0dp"
android:layout_height="match_parent"
app:barrierDirection="end"
app:barrierMargin="12dp"
app:constraint_referenced_ids="bridgeAssetInputImage" />
<TextView
android:id="@+id/bridgeAssetInputToken"
style="@style/TextAppearance.NovaFoundation.SemiBold.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:includeFontPadding="false"
android:textColor="@color/text_primary"
app:layout_constraintBottom_toTopOf="@+id/bridgeAssetInputSubtitle"
app:layout_constraintStart_toEndOf="@id/bridgeAssetInputImage"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="DOT" />
<TextView
android:id="@+id/bridgeAssetInputSubtitle"
style="@style/TextAppearance.NovaFoundation.Regular.Footnote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:includeFontPadding="false"
android:textColor="@color/text_secondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/bridgeAssetInputSubtitleImage"
app:layout_constraintTop_toBottomOf="@+id/bridgeAssetInputToken"
tools:text="Polkadot Asset Hub" />
<ImageView
android:id="@+id/bridgeAssetInputChevron"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_chevron_right"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/bridgeAssetInputToken"
app:layout_constraintStart_toEndOf="@+id/bridgeAssetInputToken"
app:layout_constraintTop_toTopOf="@+id/bridgeAssetInputToken"
app:tint="@color/icon_primary" />
<EditText
android:id="@+id/bridgeAssetInputField"
style="@style/TextAppearance.NovaFoundation.Regular.Title2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:background="@null"
android:gravity="end"
android:hint="0"
android:inputType="numberDecimal"
android:paddingTop="10dp"
android:paddingEnd="16dp"
android:paddingBottom="10dp"
android:saveEnabled="false"
android:textColor="@color/text_primary"
android:textColorHint="@color/hint_text"
android:textCursorDrawable="@null"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/bridgeAssetInputChevron"
app:layout_constraintTop_toTopOf="parent"
tools:text="4.508614" />
</androidx.constraintlayout.widget.ConstraintLayout>
</merge>