diff --git a/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt b/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt
index cdebe55b4a..492ca42a8b 100644
--- a/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt
+++ b/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt
@@ -75,6 +75,7 @@ internal class ProxyAppRouter(
try {
block()
} catch (e: Throwable) {
+ Timber.e(e)
onComplete(false)
}
}
diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt
index 7b4dfe4e57..fe714763b9 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt
@@ -101,7 +101,7 @@ internal fun LazyListScope.amountFieldV2(
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.spacedBy(16.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = modifier
.padding(top = 48.dp, bottom = 28.dp),
) {
diff --git a/core/ui/src/main/res/drawable/ic_convert_24.xml b/core/ui/src/main/res/drawable/ic_convert_24.xml
new file mode 100644
index 0000000000..3c1c407a28
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_convert_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/subcomponents/SwapAmountUpdateTrigger.kt b/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/subcomponents/SwapAmountUpdateTrigger.kt
new file mode 100644
index 0000000000..651312d68f
--- /dev/null
+++ b/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/subcomponents/SwapAmountUpdateTrigger.kt
@@ -0,0 +1,9 @@
+package com.tangem.features.swap.v2.api.subcomponents
+
+/**
+ * Trigger swap amount change from another component.
+ * Different from another triggers because it takes raw string instead of BigDecimal
+ */
+interface SwapAmountUpdateTrigger {
+ suspend fun triggerUpdateAmount(amountValue: String)
+}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/DefaultSwapAmountUpdateTrigger.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/DefaultSwapAmountUpdateTrigger.kt
new file mode 100644
index 0000000000..8be3a3c254
--- /dev/null
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/DefaultSwapAmountUpdateTrigger.kt
@@ -0,0 +1,28 @@
+package com.tangem.features.swap.v2.impl.amount
+
+import com.tangem.features.swap.v2.api.subcomponents.SwapAmountUpdateTrigger
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Trigger amount change from another component.
+ * Different from another triggers because it takes raw string instead of BigDecimal
+ */
+interface SwapAmountUpdateListener {
+ val updateAmountTriggerFlow: Flow
+}
+
+@Singleton
+internal class DefaultSwapAmountUpdateTrigger @Inject constructor() :
+ SwapAmountUpdateTrigger,
+ SwapAmountUpdateListener {
+
+ override val updateAmountTriggerFlow: Flow
+ field = MutableSharedFlow()
+
+ override suspend fun triggerUpdateAmount(amountValue: String) {
+ updateAmountTriggerFlow.emit(amountValue)
+ }
+}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponent.kt
index aeb060452e..b987f350eb 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponent.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponent.kt
@@ -38,5 +38,6 @@ internal class SwapAmountComponent @AssistedInject constructor(
interface ModelCallback : SwapNavigationModelCallback {
fun onAmountResult(amountUM: SwapAmountUM)
+ fun onSeparatorClick(lastAmount: String)
}
}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponentParams.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponentParams.kt
index beb46d4941..0f09fecef4 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponentParams.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountComponentParams.kt
@@ -1,11 +1,11 @@
package com.tangem.features.swap.v2.impl.amount
+import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
-import com.tangem.features.swap.v2.impl.swap.SwapRoute
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -27,8 +27,9 @@ internal sealed class SwapAmountComponentParams {
override val swapDirection: SwapDirection,
override val primaryCryptoCurrencyStatusFlow: StateFlow,
override val secondaryCryptoCurrency: CryptoCurrency?,
+ val title: TextReference,
val callback: SwapAmountComponent.ModelCallback,
- val currentRoute: Flow,
+ val currentRoute: Flow,
) : SwapAmountComponentParams()
data class AmountBlockParams(
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountRoute.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountRoute.kt
new file mode 100644
index 0000000000..721299ab4f
--- /dev/null
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountRoute.kt
@@ -0,0 +1,8 @@
+package com.tangem.features.swap.v2.impl.amount
+
+/**
+ * Common interface for routing to swap amount
+ */
+interface SwapAmountRoute {
+ val isEditMode: Boolean
+}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/di/SwapAmountModule.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/di/SwapAmountModule.kt
index c80a8ee734..56c67b48db 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/di/SwapAmountModule.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/di/SwapAmountModule.kt
@@ -2,10 +2,14 @@ package com.tangem.features.swap.v2.impl.amount.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
+import com.tangem.features.swap.v2.api.subcomponents.SwapAmountUpdateTrigger
+import com.tangem.features.swap.v2.impl.amount.DefaultSwapAmountUpdateTrigger
+import com.tangem.features.swap.v2.impl.amount.SwapAmountUpdateListener
import com.tangem.features.swap.v2.impl.amount.model.SwapAmountModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@@ -17,4 +21,15 @@ internal interface SwapAmountModule {
@IntoMap
@ClassKey(SwapAmountModel::class)
fun provideSwapAmountModel(impl: SwapAmountModel): Model
+}
+
+@InstallIn(SingletonComponent::class)
+@Module
+internal interface SwapAmountModuleBinds {
+
+ @Binds
+ fun provideSwapAmountUpdateTrigger(impl: DefaultSwapAmountUpdateTrigger): SwapAmountUpdateTrigger
+
+ @Binds
+ fun provideSwapAmountUpdateListener(impl: DefaultSwapAmountUpdateTrigger): SwapAmountUpdateListener
}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountClickIntents.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountClickIntents.kt
index 34cf98f664..7e5a767bb6 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountClickIntents.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountClickIntents.kt
@@ -8,4 +8,5 @@ internal interface SwapAmountClickIntents : AmountScreenClickIntents {
fun onExpandEditField(selectedAmountType: SwapAmountType)
fun onInfoClick()
fun onSelectTokenClick()
+ fun onSeparatorClick()
}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt
index 0b561eda91..81c5fc43e2 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt
@@ -8,6 +8,7 @@ import com.tangem.common.ui.amountScreen.converters.MaxEnterAmountConverter
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
import com.tangem.common.ui.navigationButtons.NavigationButton
+import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@@ -32,6 +33,7 @@ import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
import com.tangem.features.swap.v2.impl.R
import com.tangem.features.swap.v2.impl.amount.SwapAmountBlockComponent.SwapChooseProviderConfig
import com.tangem.features.swap.v2.impl.amount.SwapAmountComponentParams
+import com.tangem.features.swap.v2.impl.amount.SwapAmountUpdateListener
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountFieldUM
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountType
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
@@ -39,7 +41,6 @@ import com.tangem.features.swap.v2.impl.amount.model.converter.SwapAmountReadySt
import com.tangem.features.swap.v2.impl.amount.model.transformers.*
import com.tangem.features.swap.v2.impl.chooseprovider.SwapChooseProviderComponent
import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.SwapChooseTokenNetworkListener
-import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM.Content.DifferencePercent
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@@ -67,6 +68,7 @@ internal class SwapAmountModel @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val appRouter: AppRouter,
private val swapAlertFactory: SwapAlertFactory,
+ private val swapAmountUpdateListener: SwapAmountUpdateListener,
) : Model(), SwapAmountClickIntents, SwapChooseProviderComponent.ModelCallback {
private val params: SwapAmountComponentParams = paramsContainer.require()
@@ -99,6 +101,7 @@ internal class SwapAmountModel @Inject constructor(
}
configAmountNavigation()
subscribeOnCryptoCurrencyStatusFlow()
+ subscribeOnAmountUpdateTriggerUpdates()
observeChooseSelectToken()
// todo observe balance hiding flow
}
@@ -189,6 +192,14 @@ internal class SwapAmountModel @Inject constructor(
)
}
+ override fun onSeparatorClick() {
+ // todo send with swap make swap types
+ val amountFieldData = uiState.value.primaryAmount.amountField as? AmountState.Data
+ val callback = (params as? SwapAmountComponentParams.AmountParams)?.callback ?: return
+
+ callback.onSeparatorClick(lastAmount = amountFieldData?.amountTextField?.value.orEmpty())
+ }
+
private fun subscribeOnCryptoCurrencyStatusFlow() {
params.primaryCryptoCurrencyStatusFlow.onEach { primaryCurrencyStatus ->
primaryCryptoCurrencyStatus = primaryCurrencyStatus
@@ -210,6 +221,16 @@ internal class SwapAmountModel @Inject constructor(
}.launchIn(modelScope)
}
+ private fun subscribeOnAmountUpdateTriggerUpdates() {
+ swapAmountUpdateListener.updateAmountTriggerFlow
+ .onEach {
+ if (uiState.value is SwapAmountUM.Content) {
+ onAmountValueChange(it)
+ }
+ }
+ .launchIn(modelScope)
+ }
+
private fun observeChooseSelectToken() {
swapChooseTokenNetworkListener.swapChooseTokenNetworkResultFlow
.onEach { currency ->
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt
index 671ce82c48..212a0ca592 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/SwapAmountContent.kt
@@ -27,11 +27,9 @@ import androidx.constraintlayout.compose.ConstraintLayout
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.ui.AmountFieldV2
import com.tangem.core.ui.components.RectangleShimmer
-import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.atoms.text.EllipsisText
-import com.tangem.core.ui.components.buttons.common.TangemButtonSize
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.conditionalCompose
@@ -81,6 +79,7 @@ internal fun SwapAmountContent(
},
)
SwapAmountBlockSeparator(
+ onClick = clickIntents::onSeparatorClick,
modifier = Modifier
.constrainAs(middleButtonRef) {
top.linkTo(amountFromRef.bottom)
@@ -93,7 +92,7 @@ internal fun SwapAmountContent(
}
@Composable
-private fun SwapAmountBlockSeparator(modifier: Modifier = Modifier) {
+private fun SwapAmountBlockSeparator(onClick: () -> Unit, modifier: Modifier = Modifier) {
// todo add swap type like [Swap, SendViaSwap, SendIncognito]
Row(
verticalAlignment = Alignment.CenterVertically,
@@ -102,13 +101,11 @@ private fun SwapAmountBlockSeparator(modifier: Modifier = Modifier) {
.heightIn(max = 28.dp)
.clip(RoundedCornerShape(32.dp))
.background(TangemTheme.colors.background.secondary)
- .padding(
- vertical = 6.dp,
- horizontal = 12.dp,
- ),
+ .clickable(onClick = onClick)
+ .padding(vertical = 6.dp, horizontal = 12.dp),
) {
Text(
- text = "Convert",
+ text = stringResourceSafe(R.string.common_convert),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
)
@@ -180,8 +177,7 @@ private fun SwapAmountEditBlock(
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp),
- modifier = modifier
- .padding(vertical = 48.dp),
+ modifier = modifier.padding(top = 48.dp, bottom = 28.dp),
) {
if (amountFieldUM.amountField !is AmountState.Data) {
TextShimmer(
@@ -263,24 +259,10 @@ private fun SwapAmountInfo(
@Composable
private fun SwapAmountInfoMain(amountFieldUM: SwapAmountFieldUM, modifier: Modifier = Modifier) {
AnimatedContent(
- targetState = amountFieldUM !is SwapAmountFieldUM.Content,
+ targetState = amountFieldUM is SwapAmountFieldUM.Content,
modifier = modifier,
) { isContent ->
- if (isContent) {
- Column(
- verticalArrangement = Arrangement.spacedBy(2.dp),
- ) {
- TextShimmer(
- style = TangemTheme.typography.subtitle2,
- modifier = Modifier.width(56.dp),
- )
- TextShimmer(
- style = TangemTheme.typography.caption2,
- modifier = Modifier.width(72.dp),
- )
- }
- } else {
- val amountFieldUM = amountFieldUM as SwapAmountFieldUM.Content
+ if (isContent && amountFieldUM is SwapAmountFieldUM.Content) {
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
@@ -297,6 +279,19 @@ private fun SwapAmountInfoMain(amountFieldUM: SwapAmountFieldUM, modifier: Modif
ellipsis = amountFieldUM.subtitleEllipsis,
)
}
+ } else {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(2.dp),
+ ) {
+ TextShimmer(
+ style = TangemTheme.typography.subtitle2,
+ modifier = Modifier.width(56.dp),
+ )
+ TextShimmer(
+ style = TangemTheme.typography.caption2,
+ modifier = Modifier.width(72.dp),
+ )
+ }
}
}
}
@@ -323,8 +318,7 @@ private fun SwapAmountInfoExtra(
SwapAmountInfoQuote(
quoteUM = amountUM.selectedQuote,
swapRateType = amountUM.swapRateType,
- onSelectTokenClick =
- onSelectTokenClick,
+ onSelectTokenClick = onSelectTokenClick,
)
}
}
@@ -352,11 +346,20 @@ private fun SwapAmountInfoExtra(
@Composable
private fun AmountMaxButton(onMaxAmountClick: () -> Unit) {
- SecondaryButton(
+ Text(
text = stringResourceSafe(R.string.send_max_amount),
- size = TangemButtonSize.Small,
- onClick = onMaxAmountClick,
- modifier = Modifier.padding(end = 16.dp),
+ style = TangemTheme.typography.caption1,
+ color = TangemTheme.colors.text.primary1,
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .clip(RoundedCornerShape(16.dp))
+ .background(TangemTheme.colors.background.secondary)
+ .padding(horizontal = 12.dp, vertical = 4.dp)
+ .clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = ripple(),
+ onClick = onMaxAmountClick,
+ ),
)
}
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/preview/SwapAmountClickIntentsStub.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/preview/SwapAmountClickIntentsStub.kt
index 194e61c3d3..1c60ad739a 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/preview/SwapAmountClickIntentsStub.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/ui/preview/SwapAmountClickIntentsStub.kt
@@ -10,6 +10,8 @@ internal object SwapAmountClickIntentsStub : SwapAmountClickIntents {
override fun onSelectTokenClick() {}
+ override fun onSeparatorClick() {}
+
override fun onAmountValueChange(value: String) {}
override fun onAmountPasteTriggerDismiss() {}