diff --git a/app/src/main/java/com/tangem/tap/common/log/TangemLoggingInitializer.kt b/app/src/main/java/com/tangem/tap/common/log/TangemLoggingInitializer.kt
index a2496c3b32..a103b11bb0 100644
--- a/app/src/main/java/com/tangem/tap/common/log/TangemLoggingInitializer.kt
+++ b/app/src/main/java/com/tangem/tap/common/log/TangemLoggingInitializer.kt
@@ -98,7 +98,7 @@ class TangemLoggingInitializer(
BlockchainSdkConfig.serializer(),
environmentConfig.blockchainSdkConfig,
)
- // Drop URL-shaped values (e.g. public endpoint URLs from BlockchainSdkConfig like
+ // Drop URL-shaped drawable (e.g. public endpoint URLs from BlockchainSdkConfig like
// kaspaSecondaryApiUrl); they are not secrets and would obscure unrelated requests in logs.
val values = JsonStringValuesExtractor.extract(json)
.filter { it.isNotBlank() && !it.startsWith("http", ignoreCase = true) }
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
index 1a33b59980..db7d46a133 100644
--- a/app/src/main/res/xml/provider_paths.xml
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -1,4 +1,5 @@
+
\ No newline at end of file
diff --git a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusBottomSheet.kt b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusBottomSheet.kt
index 2dc8a4cf7a..22f48c9bef 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusBottomSheet.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusBottomSheet.kt
@@ -2,9 +2,9 @@ package com.tangem.common.ui.expressStatus
import androidx.compose.runtime.Composable
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
-import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
+import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
import com.tangem.core.ui.res.TangemTheme
data class ExpressStatusBottomSheetConfig(
@@ -18,7 +18,7 @@ fun ExpressStatusBottomSheet(config: TangemBottomSheetConfig) {
containerColor = TangemTheme.colors.background.tertiary,
) { content: ExpressStatusBottomSheetConfig ->
when (val state = content.value) {
- is ExpressTransactionStateUM.OnrampUM -> OnrampStatusBottomSheetContent(state)
+ is ExpressTransactionStateUM.OnrampUM -> OnrampStatusBottomSheetContent(state, false)
}
}
}
\ No newline at end of file
diff --git a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt
index 875515992a..c52bf8b905 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt
@@ -3,13 +3,7 @@ package com.tangem.common.ui.expressStatus
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
@@ -22,11 +16,7 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.common.ui.R
-import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
-import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
+import com.tangem.common.ui.expressStatus.state.*
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
@@ -221,13 +211,17 @@ private val PreviewExpressTransactionState: ExpressTransactionStateUM = object :
onDisposeExpressStatus = {},
iconState = ExpressTransactionStateIconUM.None,
toAmount = stringReference("0,11441958 BTC"),
+ toAmountValue = "0.11441958".toBigDecimal(),
toFiatAmount = null,
toAmountSymbol = "BTC",
toCurrencyIcon = CurrencyIconState.Loading,
+ toAddress = "0x",
fromAmount = stringReference("100 SOL"),
+ fromAmountValue = "100".toBigDecimal(),
fromFiatAmount = null,
fromAmountSymbol = "SOL",
fromCurrencyIcon = CurrencyIconState.Loading,
+ fromAddress = "0x",
)
}
// endregion
\ No newline at end of file
diff --git a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/OnrampStatusBottomSheetContent.kt b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/OnrampStatusBottomSheetContent.kt
index 2da3bcf5a8..6099a25b61 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/OnrampStatusBottomSheetContent.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/OnrampStatusBottomSheetContent.kt
@@ -9,18 +9,16 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
import com.tangem.core.ui.R
-import com.tangem.core.ui.components.SpacerH10
-import com.tangem.core.ui.components.SpacerH12
-import com.tangem.core.ui.components.SpacerH16
-import com.tangem.core.ui.components.SpacerH24
+import com.tangem.core.ui.components.*
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
@Composable
-fun OnrampStatusBottomSheetContent(state: ExpressTransactionStateUM.OnrampUM) {
+fun OnrampStatusBottomSheetContent(state: ExpressTransactionStateUM.OnrampUM, isExpressShareButtonEnabled: Boolean) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
@@ -70,6 +68,10 @@ fun OnrampStatusBottomSheetContent(state: ExpressTransactionStateUM.OnrampUM) {
isAutoDisposable = state.activeStatus.isAutoDisposable,
onClick = state.info.onDisposeExpressStatus,
)
- SpacerH24()
+ if (isExpressShareButtonEnabled) {
+ SpacerH(80.dp)
+ } else {
+ SpacerH24()
+ }
}
}
\ No newline at end of file
diff --git a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionStateUM.kt b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionStateUM.kt
index 2b7035b44d..f2c1d7ff28 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionStateUM.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/state/ExpressTransactionStateUM.kt
@@ -1,10 +1,13 @@
package com.tangem.common.ui.expressStatus.state
+import androidx.compose.runtime.Immutable
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.onramp.model.OnrampStatus
+import java.math.BigDecimal
+@Immutable
interface ExpressTransactionStateUM {
val info: ExpressTransactionStateInfoUM
@@ -35,13 +38,17 @@ data class ExpressTransactionStateInfoUM(
val onDisposeExpressStatus: () -> Unit,
val iconState: ExpressTransactionStateIconUM,
val toAmount: TextReference,
+ val toAmountValue: BigDecimal,
val toFiatAmount: TextReference?,
val toAmountSymbol: String,
val toCurrencyIcon: CurrencyIconState,
+ val toAddress: String,
val fromAmount: TextReference,
+ val fromAmountValue: BigDecimal,
val fromFiatAmount: TextReference?,
val fromAmountSymbol: String,
val fromCurrencyIcon: CurrencyIconState,
+ val fromAddress: String?,
) {
val subtitle: TextReference
get() = buildExpressStatusSubtitle(activeStatus = activeStatus, date = timestampAgoFormatted)
diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json
index 722e694df5..f6bd556683 100644
--- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json
+++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json
@@ -138,5 +138,9 @@
{
"name": "TWI_83_ADDRESS_BOOK_ENABLED",
"version": "undefined"
+ },
+ {
+ "name": "AND_15489_EXPRESS_SHARE_BUTTON_ENABLED",
+ "version": "undefined"
}
]
diff --git a/features/swap/api/src/main/kotlin/com/tangem/features/swap/SwapFeatureToggles.kt b/features/swap/api/src/main/kotlin/com/tangem/features/swap/SwapFeatureToggles.kt
index 2b975af32f..f3ea6a28c3 100644
--- a/features/swap/api/src/main/kotlin/com/tangem/features/swap/SwapFeatureToggles.kt
+++ b/features/swap/api/src/main/kotlin/com/tangem/features/swap/SwapFeatureToggles.kt
@@ -8,4 +8,5 @@ interface SwapFeatureToggles {
val isSwapProviderFilterEnabled: Boolean
val isSwapRateExperienceEnabled: Boolean
val isSwapPredefinedButtonsEnabled: Boolean
+ val isExpressShareButtonEnabled: Boolean
}
\ No newline at end of file
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapFeatureToggles.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapFeatureToggles.kt
index fc49fe82dc..79cfd4ab71 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapFeatureToggles.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/DefaultSwapFeatureToggles.kt
@@ -6,34 +6,45 @@ import com.tangem.features.swap.SwapFeatureToggles
import javax.inject.Inject
internal class DefaultSwapFeatureToggles @Inject constructor(
- featureTogglesManager: FeatureTogglesManager,
+ private val featureTogglesManager: FeatureTogglesManager,
) : SwapFeatureToggles {
- override val isYieldSwapEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED,
- )
+ override val isYieldSwapEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED,
+ )
- override val isSwapSwitchToTransferEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.AND_15207_SWAP_SWITCH_TO_TRANSFER_ENABLED,
- )
+ override val isSwapSwitchToTransferEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.AND_15207_SWAP_SWITCH_TO_TRANSFER_ENABLED,
+ )
- override val isSwapIntegratedApproveEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.AND_15120_SWAP_INTEGRATED_APPROVE,
- )
+ override val isSwapIntegratedApproveEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.AND_15120_SWAP_INTEGRATED_APPROVE,
+ )
- override val isSwapAbEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.SWAP_AB_ENABLED,
- )
+ override val isSwapAbEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.SWAP_AB_ENABLED,
+ )
- override val isSwapProviderFilterEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.AND_15009_SWAP_PROVIDER_FILTER_ENABLED,
- )
+ override val isSwapProviderFilterEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.AND_15009_SWAP_PROVIDER_FILTER_ENABLED,
+ )
- override val isSwapRateExperienceEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.AND_15103_SWAP_RATE_EXPERIENCE_ENABLED,
- )
+ override val isSwapRateExperienceEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.AND_15103_SWAP_RATE_EXPERIENCE_ENABLED,
+ )
- override val isSwapPredefinedButtonsEnabled: Boolean = featureTogglesManager.isFeatureEnabled(
- toggle = FeatureToggles.AND_15122_SWAP_PREDEFINED_BUTTONS_ENABLED,
- )
+ override val isSwapPredefinedButtonsEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.AND_15122_SWAP_PREDEFINED_BUTTONS_ENABLED,
+ )
+ override val isExpressShareButtonEnabled: Boolean
+ get() = featureTogglesManager.isFeatureEnabled(
+ toggle = FeatureToggles.AND_15489_EXPRESS_SHARE_BUTTON_ENABLED,
+ )
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt
index 78d0ad625f..dbba5c5cf0 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/express/PreviewEmptyExpressTransactionsComponent.kt
@@ -3,14 +3,7 @@ package com.tangem.features.tangempay.components.express
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.ui.Modifier
import com.tangem.common.ui.expressStatus.expressTransactionsItemsLegacy
-import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
-import com.tangem.common.ui.expressStatus.state.ExpressStatusItemState
-import com.tangem.common.ui.expressStatus.state.ExpressStatusItemUM
-import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
-import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState
+import com.tangem.common.ui.expressStatus.state.*
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.onramp.model.OnrampStatus
@@ -122,13 +115,17 @@ internal class PreviewEmptyExpressTransactionsComponent : ExpressTransactionsCom
onDisposeExpressStatus = {},
iconState = iconState,
toAmount = TextReference.Str(toAmount),
+ toAmountValue = toAmount.toBigDecimal(),
toFiatAmount = null,
toAmountSymbol = toSymbol,
toCurrencyIcon = CurrencyIconState.Empty(),
+ toAddress = "",
fromAmount = TextReference.Str(fromAmount),
+ fromAmountValue = fromAmount.toBigDecimal(),
fromFiatAmount = null,
fromAmountSymbol = fromSymbol,
fromCurrencyIcon = CurrencyIconState.Empty(),
+ fromAddress = "",
),
providerName = "Preview Provider",
providerImageUrl = "",
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt
index e2e0af401f..89fd4d64b8 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsOnrampTransactionStateConverter.kt
@@ -1,5 +1,6 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
+import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.common.ui.expressStatus.state.*
import com.tangem.common.ui.expressStatus.toActiveStatusText
import com.tangem.common.ui.expressStatus.toIconState
@@ -7,7 +8,6 @@ import com.tangem.common.ui.notifications.ExpressNotificationsUM
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
-import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
@@ -41,6 +41,7 @@ internal class TokenDetailsOnrampTransactionStateConverter(
override fun convert(value: OnrampTransaction): ExpressTransactionStateUM.OnrampUM {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
+ val statusValue = cryptoCurrencyStatus?.value
val appCurrency = appCurrencyProvider()
return ExpressTransactionStateUM.OnrampUM(
info = ExpressTransactionStateInfoUM(
@@ -63,8 +64,9 @@ internal class TokenDetailsOnrampTransactionStateConverter(
toAmount = stringReference(
value.toAmount.format { crypto(cryptoCurrency) },
),
+ toAmountValue = value.toAmount,
toFiatAmount = stringReference(
- cryptoCurrencyStatus?.value?.fiatRate?.multiply(value.toAmount).format {
+ statusValue?.fiatRate?.multiply(value.toAmount).format {
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
@@ -73,6 +75,7 @@ internal class TokenDetailsOnrampTransactionStateConverter(
),
toAmountSymbol = cryptoCurrency.symbol,
toCurrencyIcon = iconStateConverter.convert(cryptoCurrency),
+ toAddress = statusValue?.networkAddress?.defaultAddress?.value.orEmpty(),
fromAmount = stringReference(
value.fromAmount.format {
fiat(
@@ -81,12 +84,14 @@ internal class TokenDetailsOnrampTransactionStateConverter(
)
},
),
+ fromAmountValue = value.fromAmount,
fromFiatAmount = null,
fromAmountSymbol = value.fromCurrency.code,
fromCurrencyIcon = CurrencyIconState.FiatIcon(
url = value.fromCurrency.image,
fallbackResId = R.drawable.ic_currency_24,
),
+ fromAddress = null,
iconState = value.status.toIconState(),
onGoToProviderClick = { url ->
analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider())
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt
index 6cee351764..78b32deba5 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt
@@ -1,11 +1,11 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
+import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateIconUM
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
-import com.tangem.common.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
@@ -17,9 +17,9 @@ import com.tangem.core.ui.utils.mapFormattedDate
import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency
-import com.tangem.domain.models.quote.QuoteStatus
-import com.tangem.domain.models.quote.mapData
+import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
@@ -34,11 +34,11 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.E
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
+import com.tangem.utils.logging.TangemLogger
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
-import com.tangem.utils.logging.TangemLogger
import java.math.BigDecimal
// Fixme [REDACTED_JIRA]
@@ -59,7 +59,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
fun convert(
savedTransactions: List,
- quoteStatuses: Set,
+ accountStatuses: Map,
): PersistentList {
val result = mutableListOf()
@@ -69,23 +69,25 @@ internal class TokenDetailsSwapTransactionsStateConverter(
val fromCryptoCurrency = swapTransaction.fromCryptoCurrency
val toCryptoCurrencyRawId = swapTransaction.toCryptoCurrency.id.rawCurrencyId
val fromCryptoCurrencyRawId = swapTransaction.fromCryptoCurrency.id.rawCurrencyId
-
+ var fromCryptoCurrencyStatus: CryptoCurrencyStatus? = null
+ var toCryptoCurrencyStatus: CryptoCurrencyStatus? = null
swapTransaction.transactions.forEach { transaction ->
val toAmount = transaction.toCryptoAmount
val fromAmount = transaction.fromCryptoAmount
var toFiatAmount: BigDecimal? = null
var fromFiatAmount: BigDecimal? = null
- quoteStatuses.forEach { quote ->
- quote.mapData {
- if (quote.rawCurrencyId == toCryptoCurrencyRawId) {
- toFiatAmount = fiatRate.multiply(toAmount)
- }
+ accountStatuses.forEach { (account, cryptoCurrencyStatus) ->
+ if (cryptoCurrencyStatus.currency.id.rawCurrencyId == fromCryptoCurrencyRawId &&
+ account.userWalletId.stringValue == swapTransaction.fromUserWalletId
+ ) {
+ fromFiatAmount = cryptoCurrencyStatus.value.fiatRate?.multiply(fromAmount)
+ fromCryptoCurrencyStatus = cryptoCurrencyStatus
}
-
- quote.mapData {
- if (quote.rawCurrencyId == fromCryptoCurrencyRawId) {
- fromFiatAmount = fiatRate.multiply(fromAmount)
- }
+ if (cryptoCurrencyStatus.currency.id.rawCurrencyId == toCryptoCurrencyRawId &&
+ account.userWalletId.stringValue == swapTransaction.toUserWalletId
+ ) {
+ toFiatAmount = cryptoCurrencyStatus.value.fiatRate?.multiply(toAmount)
+ toCryptoCurrencyStatus = cryptoCurrencyStatus
}
}
val statusModel = transaction.status
@@ -111,6 +113,8 @@ internal class TokenDetailsSwapTransactionsStateConverter(
transaction = transaction,
toCryptoCurrency = toCryptoCurrency,
fromCryptoCurrency = fromCryptoCurrency,
+ fromCryptoCurrencyStatus = fromCryptoCurrencyStatus,
+ toCryptoCurrencyStatus = toCryptoCurrencyStatus,
toFiatAmount = toFiatAmount,
fromFiatAmount = fromFiatAmount,
),
@@ -149,14 +153,19 @@ internal class TokenDetailsSwapTransactionsStateConverter(
)
}
+ @Suppress("LongParameterList")
private fun createStateInfo(
transaction: SavedSwapTransactionModel,
toCryptoCurrency: CryptoCurrency,
fromCryptoCurrency: CryptoCurrency,
+ fromCryptoCurrencyStatus: CryptoCurrencyStatus?,
+ toCryptoCurrencyStatus: CryptoCurrencyStatus?,
toFiatAmount: BigDecimal?,
fromFiatAmount: BigDecimal?,
): ExpressTransactionStateInfoUM {
val timestamp = transaction.timestamp
+ val fromStatusValue = fromCryptoCurrencyStatus?.value
+ val toStatusValue = toCryptoCurrencyStatus?.value
return ExpressTransactionStateInfoUM(
title = resourceReference(R.string.express_exchange_by, wrappedList(transaction.provider.name)),
txId = transaction.txId,
@@ -169,13 +178,17 @@ internal class TokenDetailsSwapTransactionsStateConverter(
timestampAgoFormatted = mapFormattedDate(timestamp),
activeStatus = getActiveStatusText(transaction.status?.status),
toAmount = getCryptoAmount(transaction.toCryptoAmount, toCryptoCurrency),
+ toAmountValue = transaction.toCryptoAmount,
toFiatAmount = getFiatAmount(toFiatAmount),
toCurrencyIcon = iconStateConverter.convert(toCryptoCurrency),
toAmountSymbol = toCryptoCurrency.symbol,
+ toAddress = toStatusValue?.networkAddress?.defaultAddress?.value.orEmpty(),
fromAmount = getCryptoAmount(transaction.fromCryptoAmount, fromCryptoCurrency),
+ fromAmountValue = transaction.fromCryptoAmount,
fromFiatAmount = getFiatAmount(fromFiatAmount),
fromCurrencyIcon = iconStateConverter.convert(fromCryptoCurrency),
fromAmountSymbol = fromCryptoCurrency.symbol,
+ fromAddress = fromStatusValue?.networkAddress?.defaultAddress?.value.orEmpty(),
onClick = { clickIntents.onExpressTransactionClick(transaction.txId) },
onGoToProviderClick = { url ->
analyticsEventsHandler.send(
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt
index e2465a65bd..924b9619b7 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt
@@ -8,12 +8,13 @@ import com.tangem.datasource.local.swap.SwapTransactionStatusStore
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
+import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.currency.CryptoCurrency
-import com.tangem.domain.models.quote.QuoteStatus
+import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
-import com.tangem.domain.quotes.QuotesRepository
+import com.tangem.domain.pay.usecase.GetPaymentAccountCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.swap.domain.SwapTransactionRepository
@@ -37,8 +38,8 @@ import kotlinx.coroutines.flow.map
internal class ExchangeStatusFactory @AssistedInject constructor(
private val swapTransactionRepository: SwapTransactionRepository,
private val swapRepository: SwapRepository,
- private val quotesRepository: QuotesRepository,
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
+ private val getPaymentAccountCryptoCurrencyStatusUseCase: GetPaymentAccountCryptoCurrencyStatusUseCase,
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
private val swapTransactionStatusStore: SwapTransactionStatusStore,
private val analyticsEventsHandler: AnalyticsEventHandler,
@@ -62,19 +63,23 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
operator fun invoke(): Flow> {
return swapTransactionRepository.getTransactions(
userWallet = userWallet,
-
cryptoCurrencyId = cryptoCurrency.id,
).conflate()
.map { savedTransactions ->
- val quotes = savedTransactions
- ?.flatMap { setOf(it.fromCryptoCurrency.id, it.toCryptoCurrency.id) }
- ?.toSet()
- ?.getQuotesOrEmpty()
- ?: emptySet()
+ val accountStatuses = savedTransactions
+ ?.flatMap { swapTransaction ->
+ setOf(
+ swapTransaction.fromAccount to swapTransaction.fromCryptoCurrency,
+ swapTransaction.toAccount to swapTransaction.toCryptoCurrency,
+ )
+ }
+ ?.toMap()
+ ?.getStatuses()
+ .orEmpty()
getExchangeStatusState(
savedTransactions = savedTransactions,
- quoteStatuses = quotes,
+ accountStatuses = accountStatuses,
)
}
}
@@ -194,7 +199,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
private fun getExchangeStatusState(
savedTransactions: List?,
- quoteStatuses: Set,
+ accountStatuses: Map,
): PersistentList {
if (savedTransactions == null) {
return persistentListOf()
@@ -202,7 +207,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
return swapTransactionsStateConverter.convert(
savedTransactions = savedTransactions,
- quoteStatuses = quoteStatuses,
+ accountStatuses = accountStatuses,
)
}
@@ -226,12 +231,24 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
}
}
- private suspend fun Set.getQuotesOrEmpty(): Set {
- val rawIds = mapNotNull { it.rawCurrencyId }.toSet()
+ private suspend fun Map.getStatuses(): Map {
+ return mapNotNull { (account, cryptoCurrency) ->
+ when (account) {
+ is Account.CryptoPortfolio -> {
+ val (cryptoPortfolioAccount, currencyStatus) = getAccountCurrencyStatusUseCase.invokeSync(
+ userWalletId = account.userWalletId,
+ currency = cryptoCurrency,
+ ).getOrNull() ?: return@mapNotNull null
- return runCatching { quotesRepository.getMultiQuoteSyncOrNull(currenciesIds = rawIds) }
- .getOrNull()
- .orEmpty()
+ cryptoPortfolioAccount to currencyStatus
+ }
+ is Account.Payment -> getPaymentAccountCryptoCurrencyStatusUseCase.invokeSync(
+ userWalletId = account.userWalletId,
+ cryptoCurrency = cryptoCurrency,
+ ).getOrNull()
+ else -> null
+ }
+ }.toMap()
}
@AssistedFactory
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt
index 84897cd1c0..087e57b6d9 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt
@@ -19,6 +19,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.model.ExpressTr
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express.ExpressStatusBottomSheet
+import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.assisted.Assisted
@@ -45,6 +46,7 @@ internal class ExpressStatusFactory @AssistedInject constructor(
private val analyticsEventsHandler: AnalyticsEventHandler,
onrampStatusFactory: OnrampStatusFactory.Factory,
exchangeStatusFactory: ExchangeStatusFactory.Factory,
+ private val swapFeatureToggles: SwapFeatureToggles,
) {
private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) {
@@ -212,6 +214,7 @@ internal class ExpressStatusFactory @AssistedInject constructor(
is ExpressStatusBottomSheetConfig -> ExpressStatusBottomSheet(
config = this,
extraContent = extraContent,
+ isExpressShareButtonEnabled = swapFeatureToggles.isExpressShareButtonEnabled,
)
}
}
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt
index f334816546..4378035f1f 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheet.kt
@@ -1,14 +1,18 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.express
import android.content.res.Configuration
+import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
import com.tangem.common.ui.expressStatus.OnrampStatusBottomSheetContent
-import com.tangem.common.ui.expressStatus.state.*
-import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
+import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
+import com.tangem.core.ui.components.BottomFade
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
+import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM
@@ -17,15 +21,44 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.e
@Composable
internal fun ExpressStatusBottomSheet(
config: TangemBottomSheetConfig,
+ isExpressShareButtonEnabled: Boolean,
extraContent: (@Composable () -> Unit)? = null,
) {
TangemBottomSheet(
config = config,
containerColor = TangemTheme.colors.background.tertiary,
) { content: ExpressStatusBottomSheetConfig ->
- when (val state = content.value) {
- is ExpressTransactionStateUM.OnrampUM -> OnrampStatusBottomSheetContent(state)
- is ExchangeUM -> ExchangeStatusBottomSheetContent(state = state, extraContent = extraContent)
+ if (isExpressShareButtonEnabled) {
+ Box {
+ when (val state = content.value) {
+ is ExpressTransactionStateUM.OnrampUM -> OnrampStatusBottomSheetContent(
+ state = state,
+ isExpressShareButtonEnabled = true,
+ )
+ is ExchangeUM -> ExchangeStatusBottomSheetContent(
+ state = state,
+ extraContent = extraContent,
+ isExpressShareButtonEnabled = true,
+ )
+ }
+ BottomFade(
+ backgroundColor = TangemTheme.colors.background.tertiary,
+ modifier = Modifier.align(Alignment.BottomCenter),
+ )
+ ExpressShareContent(state = content.value)
+ }
+ } else {
+ when (val state = content.value) {
+ is ExpressTransactionStateUM.OnrampUM -> OnrampStatusBottomSheetContent(
+ state = state,
+ isExpressShareButtonEnabled = false,
+ )
+ is ExchangeUM -> ExchangeStatusBottomSheetContent(
+ state = state,
+ extraContent = extraContent,
+ isExpressShareButtonEnabled = false,
+ )
+ }
}
}
}
@@ -43,6 +76,7 @@ private fun PreviewExpressStatusBottomSheet(
onDismissRequest = {},
content = param,
),
+ isExpressShareButtonEnabled = false,
)
}
}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt
index 1a0a125cb4..cc256b1136 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/ExpressStatusBottomSheetStateProvider.kt
@@ -24,7 +24,7 @@ class ExpressStatusBottomSheetStateProvider : PreviewParameterProvider 0 && graphicsLayer.size.height > 0) {
+ val uri = graphicsLayer.saveAsShareableFile(context)
+
+ val shareIntent = if (uri != null) {
+ Intent().apply {
+ action = Intent.ACTION_SEND
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Temporary external read grant
+ putExtra(Intent.EXTRA_TEXT, shareText)
+ putExtra(Intent.EXTRA_STREAM, uri)
+ clipData = ClipData.newRawUri(null, uri)
+
+ type = "image/png"
+ }
+ } else {
+ Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_TEXT, shareText)
+ type = "text/plain"
+ }
+ }
+ context.startActivity(Intent.createChooser(shareIntent, null))
+ }
+ }
+ },
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ .align(Alignment.BottomCenter),
+ )
+ ExpressShareImageContent(
+ state = state,
+ onGraphicsLayer = { layer -> graphicsLayer = layer },
+ modifier = Modifier.size(0.dp), // size 0 so that no space is used in the UI
+ )
+ }
+}
+
+@Composable
+private fun ExpressShareImageContent(
+ state: ExpressTransactionStateUM,
+ onGraphicsLayer: (GraphicsLayer) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Box(modifier = modifier.drawForShare(onGraphicsLayer)) {
+ Box(
+ // override the parent size with desired size of the recording
+ modifier = Modifier
+ .wrapContentHeight(unbounded = true, align = Alignment.Top)
+ .wrapContentWidth(unbounded = true, align = Alignment.Start)
+ .requiredSize(525.dp, 580.dp),
+ ) {
+ Column(
+ modifier = Modifier
+ .matchParentSize()
+ .background(TangemColorPalette.Black),
+ ) {
+ Column(
+ modifier = Modifier.padding(
+ start = 40.dp,
+ end = 40.dp,
+ top = 40.dp,
+ bottom = 20.dp,
+ ),
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.img_tangem_logo_90_24),
+ contentDescription = null,
+ tint = TangemColorPalette.White,
+ )
+ SpacerH(36.dp)
+
+ ExpressShareImageAmount(
+ prefix = stringResourceSafe(R.string.common_send),
+ amountValue = state.info.fromAmountValue,
+ currencyIconState = state.info.fromCurrencyIcon,
+ currencySymbol = state.info.fromAmountSymbol,
+ )
+ ExpressShareImageAddress(
+ prefix = stringResourceSafe(R.string.common_from),
+ address = state.info.fromAddress,
+ )
+
+ SpacerH(24.dp)
+ ExpressShareImageSeparator()
+ SpacerH(24.dp)
+
+ ExpressShareImageAmount(
+ prefix = stringResourceSafe(R.string.common_receive),
+ amountValue = state.info.toAmountValue,
+ currencyIconState = state.info.toCurrencyIcon,
+ currencySymbol = state.info.toAmountSymbol,
+ )
+ ExpressShareImageAddress(
+ prefix = stringResourceSafe(R.string.common_to),
+ address = state.info.toAddress,
+ )
+ SpacerH(24.dp)
+
+ ExpressShareImageProvider(state)
+ Text(
+ text = stringResourceSafe(R.string.express_transaction_id, state.info.txExternalId.orEmpty()),
+ style = TangemTheme.typography2.bodySemibold16,
+ color = TangemTheme.colors3.text.staticDark.secondary,
+ )
+ }
+ Image(
+ painter = painterResource(R.drawable.img_share_express_background),
+ contentDescription = null,
+ modifier = Modifier,
+ contentScale = ContentScale.Crop,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun ExpressShareImageAmount(
+ prefix: String,
+ amountValue: BigDecimal,
+ currencyIconState: CurrencyIconState,
+ currencySymbol: String,
+) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Text(
+ text = prefix,
+ color = TangemTheme.colors3.text.staticDark.primary,
+ style = TangemTheme.typography2.bodySemibold16,
+ )
+ Text(
+ text = amountValue.stripZeroPlainString(),
+ color = TangemTheme.colors3.text.staticDark.primary,
+ style = TangemTheme.typography2.bodySemibold16,
+ )
+ CurrencyIcon(
+ state = currencyIconState,
+ iconSize = 20.dp,
+ shouldDisplayNetwork = false,
+ )
+ Text(
+ text = currencySymbol,
+ color = TangemTheme.colors3.text.staticDark.primary,
+ style = TangemTheme.typography2.bodySemibold16,
+ )
+ }
+}
+
+@Composable
+private fun ExpressShareImageAddress(prefix: String, address: String?) {
+ if (address != null) {
+ Text(
+ text = "$prefix:",
+ color = TangemTheme.colors3.text.staticDark.secondary,
+ )
+ Text(
+ text = address,
+ color = TangemTheme.colors3.text.staticDark.secondary,
+ )
+ }
+}
+
+@Composable
+private fun ExpressShareImageSeparator() {
+ val width = 1.dp
+ val height = 39.dp
+ val dashOnInterval = (width * 2).toPx()
+ val dashOffInterval = (width * 2).toPx()
+
+ val pathEffect = PathEffect.dashPathEffect(
+ intervals = floatArrayOf(dashOnInterval, dashOffInterval),
+ )
+ Canvas(modifier = Modifier.size(width = width, height = height)) {
+ drawLine(
+ color = TangemColorPalette.Dark2,
+ start = Offset(0f, 0f),
+ end = Offset(size.width, size.height),
+ strokeWidth = width.toPx(),
+ cap = StrokeCap.Round,
+ pathEffect = pathEffect,
+ )
+ }
+}
+
+@Composable
+private fun ExpressShareImageProvider(state: ExpressTransactionStateUM) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Text(
+ text = stringResourceSafe(R.string.express_by_provider),
+ style = TangemTheme.typography2.bodySemibold16,
+ color = TangemTheme.colors3.text.staticDark.primary,
+ )
+ val providerImageUrl = when (state) {
+ is ExchangeUM -> state.provider.imageLarge
+ is ExpressTransactionStateUM.OnrampUM -> state.providerImageUrl
+ else -> null
+ }
+ val providerName = when (state) {
+ is ExchangeUM -> state.provider.name
+ is ExpressTransactionStateUM.OnrampUM -> state.providerName
+ else -> null
+ }
+ val providerType = when (state) {
+ is ExchangeUM -> state.provider.type.providerName
+ is ExpressTransactionStateUM.OnrampUM -> state.providerType
+ else -> null
+ }
+ if (providerImageUrl != null) {
+ TangemIcon(
+ tangemIconUM = TangemIconUM.Url(providerImageUrl, fallbackRes = R.drawable.ic_empty_64),
+ modifier = Modifier.size(20.dp),
+ )
+ }
+ Text(
+ text = providerName.orEmpty(),
+ style = TangemTheme.typography2.bodySemibold16,
+ color = TangemTheme.colors3.text.staticDark.primary,
+ )
+ Text(
+ text = providerType.orEmpty(),
+ style = TangemTheme.typography2.bodySemibold16,
+ color = TangemTheme.colors3.text.staticDark.secondary,
+ )
+ }
+}
+
+@Composable
+private fun Modifier.drawForShare(onGraphicsLayer: (GraphicsLayer) -> Unit): Modifier {
+ val isInspectionMode = LocalInspectionMode.current
+
+ return drawWithCache {
+ // draw to graphics layer
+ onGraphicsLayer(
+ obtainGraphicsLayer().apply {
+ record(
+ size = IntSize(
+ width = 525.dp.toPx().toInt(),
+ height = 580.dp.toPx().toInt(),
+ ),
+ ) {
+ drawContent()
+ }
+ },
+ )
+
+ if (isInspectionMode) {
+ // draw only for preview mode
+ onDrawWithContent { drawContent() }
+ } else {
+ // leave blank to skip drawing on the screen
+ onDrawWithContent { }
+ }
+ }
+}
+
+@Suppress("MagicNumber")
+private suspend fun GraphicsLayer.saveAsShareableFile(context: Context): Uri? {
+ // convert to bitmap
+ val bitmap = this.toImageBitmap().asAndroidBitmap()
+
+ // create file
+ val cachePath = File(context.cacheDir, "images")
+ cachePath.mkdir()
+
+ val file = File(cachePath, "shared_image.png")
+
+ // write bitmap to file as PNG
+ file.outputStream().use { out ->
+ bitmap.compress(/* format = */ Bitmap.CompressFormat.PNG, /* quality = */ 100, /* stream = */ out)
+ out.flush()
+ }
+
+ // Generate secure Content URI using the registered authority
+ return FileProvider.getUriForFile(
+ /* context = */ context,
+ /* authority = */ "${context.packageName}.provider",
+ /* file = */ file,
+ )
+}
+
+@ReadOnlyComposable
+@Composable
+internal fun makeExpressShareContent(state: ExpressTransactionStateUM): String? {
+ val txExternalId = state.info.txExternalId
+ val txId = if (txExternalId != null) {
+ stringResourceSafe(R.string.express_transaction_id, txExternalId)
+ } else {
+ ""
+ }
+
+ val (providerName, providerType) = when (state) {
+ is ExchangeUM -> state.provider.name to state.provider.type
+ is ExpressTransactionStateUM.OnrampUM -> state.providerName to state.providerType
+ else -> return null
+ }
+ val providerInfo = "${stringResourceSafe(R.string.express_by_provider)} $providerName $providerType"
+ val fromAddress = if (state.info.fromAddress != null) {
+ "${stringResourceSafe(R.string.common_from)}: ${state.info.fromAddress}"
+ } else {
+ ""
+ }
+ val text = """
+ ${stringResourceSafe(R.string.common_tangem)}
+
+ ${stringResourceSafe(R.string.common_send)} ${state.info.fromAmount.resolveReference()}
+ $fromAddress
+
+ ${stringResourceSafe(R.string.common_receive)} ${state.info.toAmount.resolveReference()}
+ ${stringResourceSafe(R.string.common_to)}: ${state.info.toAddress}
+
+ $providerInfo
+ $txId
+ """.trimIndent()
+
+ return text
+}
+
+// region Preview
+@Composable
+@Preview(showBackground = true, widthDp = 360, device = Devices.PIXEL_7_PRO)
+@Preview(showBackground = true, widthDp = 360, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
+private fun ExpressShareImageContent_Preview(
+ @PreviewParameter(ExpressStatusBottomSheetStateProvider::class) param: ExpressStatusBottomSheetConfig,
+) {
+ TangemThemePreviewRedesign {
+ ExpressShareImageContent(param.value, {}, modifier = Modifier)
+ }
+}
+
+// endregion
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt
index 6ce01c5bd9..3f4557962e 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/express/exchange/ExchangeStatusBottomSheetContent.kt
@@ -10,10 +10,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
import com.tangem.common.ui.expressStatus.ExpressEstimate
import com.tangem.common.ui.expressStatus.ExpressHideButton
import com.tangem.common.ui.expressStatus.ExpressProvider
import com.tangem.core.ui.R
+import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH10
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.components.SpacerH16
@@ -28,7 +30,11 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component
import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM
@Composable
-internal fun ExchangeStatusBottomSheetContent(state: ExchangeUM, extraContent: (@Composable () -> Unit)? = null) {
+internal fun ExchangeStatusBottomSheetContent(
+ state: ExchangeUM,
+ isExpressShareButtonEnabled: Boolean,
+ extraContent: (@Composable () -> Unit)? = null,
+) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
@@ -87,7 +93,11 @@ internal fun ExchangeStatusBottomSheetContent(state: ExchangeUM, extraContent: (
isAutoDisposable = state.activeStatus?.isAutoDisposable == true,
onClick = state.info.onDisposeExpressStatus,
)
- SpacerH24()
+ if (isExpressShareButtonEnabled) {
+ SpacerH(80.dp)
+ } else {
+ SpacerH24()
+ }
}
}
diff --git a/features/tokendetails/impl/src/main/res/drawable/img_share_express_background.webp b/features/tokendetails/impl/src/main/res/drawable/img_share_express_background.webp
new file mode 100644
index 0000000000..5fafc633ee
Binary files /dev/null and b/features/tokendetails/impl/src/main/res/drawable/img_share_express_background.webp differ
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt
index 597e1b1837..727cfd9ca5 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/SingleWalletOnrampTransactionConverter.kt
@@ -63,6 +63,7 @@ internal class SingleWalletOnrampTransactionConverter(
timestampAgoFormatted = mapFormattedDate(value.timestamp),
activeStatus = value.status.toActiveStatusText(currency.name),
toAmount = stringReference(value.toAmount.format { crypto(currency) }),
+ toAmountValue = value.toAmount,
toFiatAmount = stringReference(
status.fiatRate?.multiply(value.toAmount).format {
fiat(
@@ -73,6 +74,7 @@ internal class SingleWalletOnrampTransactionConverter(
),
toAmountSymbol = currency.symbol,
toCurrencyIcon = iconStateConverter.convert(currency),
+ toAddress = status.networkAddress?.defaultAddress?.value.orEmpty(),
fromAmount = stringReference(
value.fromAmount.format {
fiat(
@@ -81,12 +83,14 @@ internal class SingleWalletOnrampTransactionConverter(
)
},
),
+ fromAmountValue = value.fromAmount,
fromFiatAmount = null,
fromAmountSymbol = value.fromCurrency.code,
fromCurrencyIcon = CurrencyIconState.FiatIcon(
url = value.fromCurrency.image,
fallbackResId = R.drawable.ic_currency_24,
),
+ fromAddress = null,
iconState = value.status.toIconState(),
onGoToProviderClick = { url ->
analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider())