Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing a transaction type. #2026

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ enum class TransactionViewType {
CREATION,
REJECTION,
REJECTION_QUEUED,
SWAP_ORDER,
SWAP_ORDER_QUEUED,
CONFLICT
}

Expand All @@ -62,6 +64,8 @@ class TransactionViewHolderFactory : BaseFactory<BaseTransactionViewHolder<Trans
TransactionViewType.CONFLICT.ordinal -> ConflictViewHolder(viewBinding as ItemTxConflictTxBinding, this)
TransactionViewType.REJECTION.ordinal -> RejectionViewHolder(viewBinding as ItemTxRejectionBinding)
TransactionViewType.REJECTION_QUEUED.ordinal -> RejectionQueuedViewHolder(viewBinding as ItemTxQueuedRejectionBinding)
TransactionViewType.SWAP_ORDER.ordinal -> SwapOrderViewHolder(viewBinding as ItemTxSwapOrderBinding)
TransactionViewType.SWAP_ORDER_QUEUED.ordinal -> SwapOrderQueuedViewHolder(viewBinding as ItemTxQueuedSwapOrderBinding)
else -> throw UnsupportedViewType(javaClass.name)
} as BaseTransactionViewHolder<TransactionView>

Expand All @@ -80,6 +84,8 @@ class TransactionViewHolderFactory : BaseFactory<BaseTransactionViewHolder<Trans
TransactionViewType.CONFLICT.ordinal -> ItemTxConflictTxBinding.inflate(layoutInflater, parent, false)
TransactionViewType.REJECTION.ordinal -> ItemTxRejectionBinding.inflate(layoutInflater, parent, false)
TransactionViewType.REJECTION_QUEUED.ordinal -> ItemTxQueuedRejectionBinding.inflate(layoutInflater, parent, false)
TransactionViewType.SWAP_ORDER.ordinal -> ItemTxSwapOrderBinding.inflate(layoutInflater, parent, false)
TransactionViewType.SWAP_ORDER_QUEUED.ordinal -> ItemTxQueuedSwapOrderBinding.inflate(layoutInflater, parent, false)
else -> throw UnsupportedViewType(javaClass.name)
}

Expand All @@ -99,6 +105,8 @@ class TransactionViewHolderFactory : BaseFactory<BaseTransactionViewHolder<Trans
is TransactionView.Conflict -> TransactionViewType.CONFLICT
is TransactionView.RejectionTransaction -> TransactionViewType.REJECTION
is TransactionView.RejectionTransactionQueued -> TransactionViewType.REJECTION_QUEUED
is TransactionView.SwapOrderTransaction -> TransactionViewType.SWAP_ORDER
is TransactionView.SwapOrderTransactionQueued -> TransactionViewType.SWAP_ORDER_QUEUED
}.ordinal
}

Expand Down Expand Up @@ -318,6 +326,62 @@ class ContractInteractionViewHolder(private val viewBinding: ItemTxContractInter
}
}

class SwapOrderQueuedViewHolder(private val viewBinding: ItemTxQueuedSwapOrderBinding) :
BaseTransactionViewHolder<TransactionView.SwapOrderTransactionQueued>(viewBinding) {

@OptIn(ExperimentalTime::class)
override fun bind(viewTransfer: TransactionView.SwapOrderTransactionQueued, payloads: List<Any>) {
val resources = viewBinding.root.context.resources
val theme = viewBinding.root.context.theme

with(viewBinding) {
status.setText(viewTransfer.statusText)
status.setTextColor(ResourcesCompat.getColor(resources, viewTransfer.statusColorRes, theme))

dateTime.text = viewTransfer.dateTime.elapsedIntervalTo(Date.from(Instant.now())).format(resources)
addressName.text = resources.getString(R.string.tx_list_swap_order)

confirmationsIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, viewTransfer.confirmationsIcon, theme))
confirmations.setTextColor(ResourcesCompat.getColor(resources, viewTransfer.confirmationsTextColor, theme))
confirmations.text = resources.getString(R.string.tx_list_confirmations, viewTransfer.confirmations, viewTransfer.threshold)

nonce.text = viewTransfer.nonce

root.setOnClickListener {
navigateToTxDetails(it, viewTransfer.chain, viewTransfer.id)
}
}
}
}

class SwapOrderViewHolder(private val viewBinding: ItemTxSwapOrderBinding) :
BaseTransactionViewHolder<TransactionView.SwapOrderTransaction>(viewBinding) {

override fun bind(viewTransfer: TransactionView.SwapOrderTransaction, payloads: List<Any>) {
val resources = viewBinding.root.context.resources
val theme = viewBinding.root.context.theme

with(viewBinding) {
finalStatus.setText(viewTransfer.statusText)
finalStatus.setTextColor(ResourcesCompat.getColor(resources, viewTransfer.statusColorRes, theme))
dateTime.text = viewTransfer.dateTimeText

nonce.text = viewTransfer.nonce
addressName.text = resources.getString(R.string.tx_list_swap_order)

addressLogo.alpha = viewTransfer.alpha
addressName.alpha = viewTransfer.alpha
finalStatus.alpha = OPACITY_FULL
dateTime.alpha = viewTransfer.alpha
nonce.alpha = viewTransfer.alpha

root.setOnClickListener {
navigateToTxDetails(it, viewTransfer.chain, viewTransfer.id)
}
}
}
}

private fun Resources.getAction(methodName: String?, actionCount: Int?): String? =
if (actionCount != null) {
if (actionCount > 0) this.getQuantityString(R.plurals.tx_list_actions, actionCount, actionCount) else methodName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ class TransactionListViewModel
val owner = localOwners.find { it.address == txInfo.creator.value }
toHistoryCreation(chain, txInfo, owner)
}
is TransactionInfo.SwapOrder -> toSwapOrderTransactionView(chain, txInfo, needsYourConfirmation, isConflict)
TransactionInfo.Unknown -> TransactionView.Unknown
}
}
Expand Down Expand Up @@ -366,6 +367,60 @@ class TransactionListViewModel
)
}

private fun Transaction.toSwapOrderTransactionView(
chain: Chain,
txInfo: TransactionInfo.SwapOrder,
needsYourConfirmation: Boolean,
isConflict: Boolean
): TransactionView =
if (!isCompleted(txStatus)) queuedSwapOrderTransaction(chain, txInfo, needsYourConfirmation, isConflict)
else historicSwapOrderTransaction(chain, txInfo)

private fun Transaction.historicSwapOrderTransaction(
chain: Chain,
txInfo: TransactionInfo.SwapOrder
): TransactionView.SwapOrderTransaction {

return TransactionView.SwapOrderTransaction(
chain = chain,
id = id,
status = txStatus,
statusText = displayString(txStatus),
statusColorRes = statusTextColor(txStatus),
dateTimeText = timestamp.formatBackendTimeOfDay(),
alpha = alpha(txStatus),
nonce = executionInfo?.nonce?.toString() ?: "",
explorerUrl = txInfo.explorerUrl
)
}

private fun Transaction.queuedSwapOrderTransaction(
chain: Chain,
txInfo: TransactionInfo.SwapOrder,
needsYourConfirmation: Boolean,
isConflict: Boolean
): TransactionView.SwapOrderTransactionQueued {

//FIXME this wouldn't make sense for incoming Ethereum TXs
val threshold = executionInfo?.confirmationsRequired ?: -1
val thresholdMet = checkThreshold(threshold, executionInfo?.confirmationsSubmitted)

return TransactionView.SwapOrderTransactionQueued(
chain = chain,
id = id,
status = txStatus,
statusText = displayString(txStatus, needsYourConfirmation),
statusColorRes = statusTextColor(txStatus),
dateTime = timestamp,
confirmations = executionInfo?.confirmationsSubmitted ?: 0,
threshold = threshold,
confirmationsTextColor = if (thresholdMet) R.color.success else R.color.icon,
confirmationsIcon = if (thresholdMet) R.drawable.ic_confirmations_green_16dp else R.drawable.ic_confirmations_grey_16dp,
nonce = if (isConflict) "" else executionInfo?.nonce?.toString() ?: "",
explorerUrl = txInfo.explorerUrl
)
}

private fun Transaction.toRejectionTransactionView(
chain: Chain,
awaitingYourConfirmation: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,33 @@ sealed class TransactionView(
val addressInfo: AddressInfoData
) : TransactionView(status, id, chain)

data class SwapOrderTransaction(
override val id: String,
override val status: TransactionStatus,
override val chain: Chain,
@StringRes val statusText: Int,
@ColorRes val statusColorRes: Int,
val dateTimeText: String,
val alpha: Float,
val nonce: String,
val explorerUrl: String
) : TransactionView(status, id, chain)

data class SwapOrderTransactionQueued(
override val id: String,
override val status: TransactionStatus,
override val chain: Chain,
@StringRes val statusText: Int,
@ColorRes val statusColorRes: Int,
val dateTime: Date,
val confirmations: Int,
val threshold: Int,
@ColorRes val confirmationsTextColor: Int,
@DrawableRes val confirmationsIcon: Int,
val nonce: String,
val explorerUrl: String
) : TransactionView(status, id, chain)

data class Creation(
override val id: String,
override val status: TransactionStatus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import io.gnosis.safe.ui.transactions.details.viewdata.TransactionDetailsViewDat
import io.gnosis.safe.ui.transactions.details.viewdata.TransactionInfoViewData
import io.gnosis.safe.utils.*
import pm.gnosis.model.Solidity
import pm.gnosis.svalinn.common.utils.openUrl
import pm.gnosis.svalinn.common.utils.snackbar
import pm.gnosis.svalinn.common.utils.visible
import pm.gnosis.utils.asEthereumAddress
Expand Down Expand Up @@ -256,6 +257,11 @@ class TransactionDetailsFragment : BaseViewBindingFragment<FragmentTransactionDe
binding.advancedDivider.visible(false)
}

if (txDetails.txInfo !is TransactionInfoViewData.SwapOrder) {
binding.etherscanDivider.visible(false)
binding.orderLink.visible(false)
}

when (val txInfo = txDetails.txInfo) {
is TransactionInfoViewData.Transfer -> {
val viewStub = binding.stubTransfer
Expand Down Expand Up @@ -443,6 +449,30 @@ class TransactionDetailsFragment : BaseViewBindingFragment<FragmentTransactionDe
)
}
}
is TransactionInfoViewData.SwapOrder -> {
val viewStub = binding.stubCustom
if (viewStub.parent != null) {
contentBinding = TxDetailsCustomBinding.bind(viewStub.inflate())
}
val txDetailsCustomBinding = contentBinding as TxDetailsCustomBinding
with(txDetailsCustomBinding) {
txAction.visible(false)
txDataDecoded.visible(false)
txDataDecodedSeparator.visible(false)

txStatus.setStatus(
title = resources.getString(TxType.SWAP_ORDER.titleRes),
defaultIconRes = TxType.SWAP_ORDER.iconRes,
statusTextRes = getStringResForStatus(txDetails.txStatus, txDetails.canSign && awaitingConfirmations),
statusColorRes = getColorForStatus(txDetails.txStatus)
)
binding.etherscanDivider.visible(true)
binding.orderLink.visible(true)
binding.orderLink.setOnClickListener {
requireContext().openUrl(txInfo.explorerUrl)
}
}
}
}

binding.content.visible(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ enum class TxType(@DrawableRes val iconRes: Int, @StringRes val titleRes: Int) {
TRANSFER_OUTGOING(R.drawable.ic_arrow_red_10dp, R.string.tx_status_type_transfer_outgoing),
MODIFY_SETTINGS(R.drawable.ic_settings_change_14dp, R.string.tx_status_type_modify_settings),
CUSTOM(R.drawable.ic_code_16dp, R.string.tx_status_type_custom),
SWAP_ORDER(R.drawable.ic_code_16dp, R.string.tx_status_type_swap_order),
CREATION(R.drawable.ic_settings_change_14dp, R.string.tx_status_type_creation),
REJECTION(R.drawable.ic_circle_cross_red_16dp, R.string.tx_status_type_rejection)
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ sealed class TransactionInfoViewData(
val addressUri: String?
) : TransactionInfoViewData(TransactionType.Custom)

@Parcelize
data class SwapOrder(
val uid: String,
val explorerUrl: String
) : TransactionInfoViewData(TransactionType.SwapOrder)

@Parcelize
object Unknown : TransactionInfoViewData(TransactionType.Unknown)
}
Expand Down Expand Up @@ -244,6 +250,7 @@ internal fun TransactionInfo.toTransactionInfoViewData(
dataDecoded,
settingsInfo.toSettingsInfoViewData(safes, owners = owners)
)
is TransactionInfo.SwapOrder -> TransactionInfoViewData.SwapOrder(uid, explorerUrl)
is TransactionInfo.Transfer -> {
val addressInfoData =
if (direction == TransactionDirection.OUTGOING) {
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/io/gnosis/safe/utils/TxUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ fun TransactionInfoViewData.formattedAmount(chain: Chain, balanceFormatter: Bala
is TransactionInfoViewData.SettingsChange -> "0 ${chain.currency.symbol}"
is TransactionInfoViewData.Creation -> "0 ${chain.currency.symbol}"
is TransactionInfoViewData.Rejection -> "0 ${chain.currency.symbol}"
is TransactionInfoViewData.SwapOrder -> "0 ${chain.currency.symbol}"
TransactionInfoViewData.Unknown -> "0 ${chain.currency.symbol}"
}

Expand All @@ -87,6 +88,7 @@ fun TransactionInfoViewData.logoUri(chain: Chain): String? =
}
}
is TransactionInfoViewData.Custom,
is TransactionInfoViewData.SwapOrder,
is TransactionInfoViewData.SettingsChange,
is TransactionInfoViewData.Creation,
is TransactionInfoViewData.Rejection,
Expand Down
20 changes: 19 additions & 1 deletion app/src/main/res/layout/fragment_transaction_details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,28 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/item_setting_openable_height"
android:layout_marginStart="16dp"
android:drawablePadding="6dp"
android:gravity="start|center_vertical"
android:text="@string/tx_details_view_on_block_explorer"
app:drawableEndCompat="@drawable/ic_link_green_24dp" />

<View
android:id="@+id/etherscan_divider"
android:layout_width="match_parent"
android:layout_height="@dimen/item_separator_height"
android:background="@color/separator" />

<TextView
android:id="@+id/order_link"
style="@style/TextLink"
android:layout_width="wrap_content"
android:layout_height="@dimen/item_setting_openable_height"
android:layout_marginStart="16dp"
app:drawableEndCompat="@drawable/ic_link_green_24dp"
android:drawablePadding="6dp"
android:gravity="start|center_vertical"
android:text="@string/tx_details_view_on_block_explorer" />
android:text="@string/tx_details_view_swap_order" />


</LinearLayout>

Expand Down
Loading
Loading