diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml
index 41c4f24cdb..8f4bc4a262 100644
--- a/core/res/src/main/res/values-de/strings.xml
+++ b/core/res/src/main/res/values-de/strings.xml
@@ -313,6 +313,7 @@
- %dStunden her
Importieren
+ in
In Arbeit
Unzureichende Mittel
Später
@@ -398,6 +399,7 @@
An
Zu %s
Heute
+ Token
Zu sendendes Token
- %d Token
diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml
index f7bc36a8d3..b385282be7 100644
--- a/core/res/src/main/res/values-es/strings.xml
+++ b/core/res/src/main/res/values-es/strings.xml
@@ -309,6 +309,7 @@
- Hace %dh
Importe
+ en
En progreso
Fondos insuficientes
Más tarde
@@ -394,6 +395,7 @@
A
A %s
Hoy
+ Token
Token para enviar
- %d token
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index 8faa21a926..2835248f7c 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -309,6 +309,7 @@
- Il y a %dh
Importez
+ dans
En cours
Plus tard
En savoir plus
@@ -392,6 +393,7 @@
À
À %s
Aujourd\'hui
+ Token
- %d token
- %d tokens
diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml
index 1b7dd158fb..45d98693f9 100644
--- a/core/res/src/main/res/values-it/strings.xml
+++ b/core/res/src/main/res/values-it/strings.xml
@@ -16,12 +16,14 @@
Fatto
Errore
Impossibile ottenere la commissione
+ in
Costi della rete
OK
Mantieni le modifiche
Invia
Impossibile inviare la transazione
Con successo
+ Token
- %d gettone
- %d gettoni
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index b500909414..a9db096537 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -214,6 +214,7 @@
アクセスが拒否されました
アカウント
アカウント
+ %s に失敗しました
有効化
追加
資金を追加
@@ -230,6 +231,8 @@
適用する
承認
承認
+ 承認済み
+ 承認中
注意
利用可能なネットワーク
バックアップ
@@ -309,10 +312,14 @@
非表示
%sまで長押し
時間
+
+ - %d 時間
+
- %d時間前
インポート
+ で
進行中
残高不足
後で
@@ -355,6 +362,8 @@
%1$s — %2$s
続きを読む
受け取る
+ 受け取り済み
+ 受け取り中
おすすめ
拒否
リロード
@@ -373,6 +382,8 @@
送る
送金:
取引の送信に失敗しました
+ 送金中
+ 送金済み
サーバーが利用できません。しばらくしてからもう一度お試しください。
共有
リンクを共有
@@ -383,6 +394,7 @@
スキップ
問題が発生しました
ステーキング
+ ステーキング済み
ステーキング
始める
送信
@@ -390,6 +402,8 @@
サポート
対応ネットワーク
スワップ
+ スワップ済み
+ スワップ中
Tangem
Tangem Wallet
タップして長押し
@@ -398,6 +412,7 @@
宛先
%sへ
今日
+ トークン
送信するトークン
- %d トークン
@@ -406,6 +421,7 @@
取引状況
取引
送金
+ 送金済み
データを読み込めません…
わかりました
理解して続行
@@ -415,10 +431,12 @@
ステーキング解除
%1$sの制限により、1つのトランザクションに収まるUTXOは%2$d個のみです。つまり、 %3$s以下しか送信できません。量を減らす必要があります。
値がコピーされました
+ 投票
ウォレット
警告
週
で
+ 引き出し中
はい
利息モード
コントラクトアドレスをコピーしました!
@@ -580,12 +598,14 @@
ベストレート
FCA警告リスト
固定レートは利用できません
+ スワッププロバイダー
お得なレート
FCA警告リストに掲載されたプロバイダー
最大 %s まで使用可能
%s 以上で利用可能
このペアは利用できません
許可が必要です
+ 権限が必要です
推奨
%sを買い付けました
%sを買い付けています
@@ -633,6 +653,7 @@
承認機能は、別のアドレスに特定の量のトークンを使用する許可を与えるために必要です。設計上スマートコントラクトは、承認しない限りトークンにアクセスできません。トークンを「ロック解除」すると、StakeKitスマート コントラクトがトークンを使用する権限が与えられます。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためにガス料金(あなたが支払う)を受け取ります。承認後、トークンをステーキングできます。
続行するには、Polygonスマートコントラクトが%sを使用することを許可する必要があります
続行するには、%1sスマートコントラクトに%2sを使用する権限を付与してください
+ 分散型取引所がウォレットと連携するには、許可が必要です。%1s
許可を与える
無制限
アドレスはTangemハードウェアウォレット上で直接生成され、そのまま安全に使用できます。
@@ -660,6 +681,8 @@
暗号資産をオフラインで厳重保管。カードサイズで、金庫以上の安心を。
実行すると、最初からやり直す必要があります。
Googleドライブのバックアップから既存のウォレットを復元する
+ ウォレットの復元をさらに簡単にするため、Googleドライブバックアップ機能を準備しています。
+ Googleドライブバックアップは近日対応予定です
Googleドライブのバックアップ
さらに強固なセキュリティのために、新しいウォレットを作成して資産を移動しましょう。
新しいウォレットを作成
@@ -1103,6 +1126,8 @@
別の方法を選択してください。
現地の規制要件に準拠するため、%@の利用には本人確認が必要です。
決済プロバイダーによる本人確認が必要です。
+ 認証する
+ 重要事項
オンランプ機能を使用することにより、プロバイダの%1$sおよび%2$sに同意するものとします
サービスは外部プロバイダーによって提供されます。 \nTangemは責任を負いません。
買付金額は%s以下にしてください
@@ -1166,7 +1191,11 @@
不明なパラメータ
クレジットカードまたは銀行口座
アドレスまたはQRコードを共有してください
+ 暗号資産を安全に売却
+ 別のウォレットに送信
ポートフォリオ間で
+ その他
+ クイック入金
メモ不要
%3$sネットワーク上の%1$s ( %2$s )
%2$sネットワーク上の%1$s
@@ -1522,6 +1551,7 @@
承認すると、このスマートコントラクトが今後の取引でトークンを利用できるようになります。
固定レート
ネットワークは、あなたがトークンのスワップを承認していることを確認するために、トークン承認手数料を請求します。
+ スワップ中
より多くのトークンをより良いレートで、ウォレット内にて直接交換します。
新しいスワッププロバイダーが利用可能になりました!
他のものをお探しですか?\n検索してみるか、別の暗号資産をチェックしてみましょう!
@@ -1530,11 +1560,11 @@
24時間体制のサポートであらゆる問題に対応します。
いつもここに
複数の信頼できるプロバイダーが一箇所に集結。ウォレット内で様々な暗号資産を簡単に交換できます。
- Tangem内で暗号資産を直接交換\n追加の送金は不要\n取引所に資産を移す必要なし
+ Tangem内で暗号資産を直接交換できます\n追加の送金は不要です\n取引所に資金を移す必要もありません
ぜひスワップしてください
ウォレット内でスワップ
失敗も死角もありません。取引は常に保護されます。
- スワップは信頼できるプロバイダーを通じて実行されます。秘密鍵は常にTangemウォレット内に保持されます。シンプル。透明。自己管理。
+ スワップは信頼できるプロバイダーを通じて実行されます。秘密鍵は常にTangemウォレット内に保持されます。明確で、透明性が高く、自己管理型です。
難攻不落の防御
主導権はあなたの手にあります
幅広いネットワークの中から、常に最適なプロバイダーと料金レートを選択します
@@ -1555,7 +1585,9 @@
すべての分散型取引所は、スマートコントラクトがあなたの許可なくウォレットにアクセスするのを防ぐために承認を必要とします。設計上、スマートコントラクトは承認なしでトークンにアクセスできません。トークンを「ロック解除」することで、あなたは1-inchのスマートコントラクトがトークンを使うことを承認します。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためのガス料金(あなたが支払う)を受け取ります。承認後、トークンを交換することができます。
承認
手数料見積りエラーです。サポートにフィードバックをお送りください。
+ 送信元
スワップする
+ 送信
選択したトークンをこの量を交換すると、価格に大きな影響が生じ、結果が減少します。
流動性が低いため、受取額が大幅に少なくなる可能性があります。金額を減らすか、別のプロバイダーをお試しください。
価格への影響が甚大です
@@ -1564,11 +1596,14 @@
許可を与える
スワップ
スワップ中…
+ 受け取り先
受け取る
トークンを選択
利用不可
この取引に十分な流動性がありません。\n金額を減らすか、別のプロバイダーを選択してください。
取引額が大きすぎます
+ 送金
+ 送金...
皆様からのフィードバックをお待ちしております
Tangem Payのベータ版を公開しました
カード名を変更できません
@@ -1657,6 +1692,7 @@
現在、出金ができません
現在の処理が完了するまでは、スワップや新しい出金を開始することはできません。
出金処理中です
+ カード名
%s以上の金額を設定してください
限度額を設定できませんでした。もう一度お試しください
変更
@@ -1708,6 +1744,8 @@
余計な費用なしで、表示金額のみを支払う
あなたの住所や資産を開示することなく、個別の支払い用アカウントが作成されます。
他に類を見ないプライバシー
+ そして支払いカードを連携します
+ ウォレットを設定します
無料のTangem Payカードを数分でゲットしましょう
Payサポート
支払いアカウント
@@ -1757,7 +1795,7 @@
承認が取り消されましたが、あなたの資金は引き続き利息モードです。操作を行うには、利息モードに移動し、再度承認を付与してください。
利用可能残高
合計残高
- 年間で最大%sを獲得
+ 年利最大%s
XPUBを生成する
非表示
このトークンをメイン画面から非表示にします。トークンの管理ページからいつでも再度追加できます。
@@ -1783,12 +1821,21 @@
売却できません
%sからのスワップは利用できません
スワップはできません
+ 報酬を請求中
コントラクト: %s
+ 利息モードを無効化中
+ ステーキングで獲得した金額
まだ取引はありません
取引履歴の読み込みに失敗しました。\n情報を更新するには、リロードボタンをクリックしてください。
+ %%image%% %s から
複数のアドレス
現在、このブロックチェーンでは取引履歴はサポートされていません。しかしご心配なく!弊社で対応中です。その間、エクスプローラーで確認することができます。
オペレーション
+ 保留中
+ 報酬を再ステーキングしました
+ 報酬の再ステーキング
+ ステーキング報酬
+ %%image%% %s へ
対象:%s
送金元: %s
送金先: %s
@@ -2064,7 +2111,7 @@
MATICはPOLに移行中です。ただし、期限は設定されておらず、MATICはまだ廃止されていません。MATICトークンを引き続き安全に使用することも、POLに交換することもできます。
MATICからPOLへの移行
- - %d ネットワークのアドレスを取得するために、カードまたはリングを利用してください
+ - カードまたはリングを使って、[%i}ネットワークのアドレスを取得します
一部のアドレスが見つかりません
現在、ネットワークにアクセスできません。しばらくしてからもう一度お試しください。
diff --git a/core/res/src/main/res/values-pt-rBR/strings.xml b/core/res/src/main/res/values-pt-rBR/strings.xml
index 4cd264c962..cc86f5186c 100644
--- a/core/res/src/main/res/values-pt-rBR/strings.xml
+++ b/core/res/src/main/res/values-pt-rBR/strings.xml
@@ -320,6 +320,7 @@
- OUTRO
Importar
+ em
Em andamento
Saldo insuficiente
Mais tarde
@@ -407,6 +408,7 @@
Para
Para %s
Hoje
+ Token
Token a ser enviado
- token
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 5f7b583b7d..39a182aab0 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -339,6 +339,7 @@
- %dч назад
Импортировать
+ в
В процессе
Недостаточный баланс
Позже
@@ -429,6 +430,7 @@
На
На %s
Сегодня
+ Токен
Токен к отправке
- %d токен
diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml
index 0e1fecd93d..ed08a77c16 100644
--- a/core/res/src/main/res/values-uk-rUA/strings.xml
+++ b/core/res/src/main/res/values-uk-rUA/strings.xml
@@ -321,6 +321,7 @@
- %d годин тому
Імпортувати
+ у
В процесі
Пізніше
Дізнатися більше
@@ -408,6 +409,7 @@
До
На %s
Сьогодні
+ Токен
- %d токен
- %d токени
diff --git a/core/res/src/main/res/values-zh-rCN/strings.xml b/core/res/src/main/res/values-zh-rCN/strings.xml
index 336648fd49..21d712ae21 100644
--- a/core/res/src/main/res/values-zh-rCN/strings.xml
+++ b/core/res/src/main/res/values-zh-rCN/strings.xml
@@ -312,6 +312,7 @@
- 小时之前
导入
+ 在
进行中
余额不足
稍后
@@ -397,6 +398,7 @@
至
到 %s
今天
+ 代币
要发送的代币
- %d代币
diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml
index 69ae0df956..bd779ef436 100644
--- a/core/res/src/main/res/values-zh-rTW/strings.xml
+++ b/core/res/src/main/res/values-zh-rTW/strings.xml
@@ -68,6 +68,7 @@
錯誤
獲取費用失敗
導入
+ 在
進行中
網路費
否
@@ -92,6 +93,7 @@
成功
交換
條款和條件
+ 代幣
- %d 代幣
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index a986955bd5..b85f6fa201 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -327,6 +327,7 @@
- %dh ago
Import
+ in
In progress
Insufficient balance
Later
@@ -421,6 +422,7 @@
To
To %s
Today
+ Token
Token to send
- %d token
@@ -1578,8 +1580,10 @@
The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap.
Swap in progress
Exchange more tokens at better rates directly in your wallet.
+ Detailed mode
New Swap Provider Available!
Looking for something else?\nTry searching or explore another crypto!
+ Simple mode
Search for any token, even if it’s not in your list yet.
Use search to find what you need
Feel confident with round-the-clock support to help with any issues
diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt
index 2f5e08ccf7..f30d3ef92f 100644
--- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt
+++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt
@@ -21,6 +21,7 @@ import com.tangem.datasource.exchangeservice.swap.ExpressUtils
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
+import com.tangem.datasource.local.preferences.utils.storeObject
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.express.models.ExpressOperationType
import com.tangem.domain.models.currency.CryptoCurrency
@@ -419,4 +420,8 @@ internal class DefaultSwapRepository(
override suspend fun getStoredSwapUiMode(): SwapUIMode? {
return appPreferencesStore.getObjectSyncOrNull(PreferencesKeys.SWAP_UI_MODE_KEY)
}
+
+ override suspend fun storeSwapUiMode(mode: SwapUIMode) {
+ appPreferencesStore.storeObject(PreferencesKeys.SWAP_UI_MODE_KEY, mode)
+ }
}
\ No newline at end of file
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SetSwapUiModeUseCase.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SetSwapUiModeUseCase.kt
new file mode 100644
index 0000000000..90055925d2
--- /dev/null
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SetSwapUiModeUseCase.kt
@@ -0,0 +1,13 @@
+package com.tangem.feature.swap.domain
+
+import com.tangem.feature.swap.domain.api.SwapRepository
+import com.tangem.feature.swap.domain.models.domain.SwapUIMode
+
+class SetSwapUiModeUseCase(
+ private val swapRepository: SwapRepository,
+) {
+
+ suspend operator fun invoke(mode: SwapUIMode) {
+ swapRepository.storeSwapUiMode(mode)
+ }
+}
\ No newline at end of file
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt
index fbc9f2828a..fb7b0b78ab 100644
--- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt
@@ -77,4 +77,6 @@ interface SwapRepository {
): Either
suspend fun getStoredSwapUiMode(): SwapUIMode?
+
+ suspend fun storeSwapUiMode(mode: SwapUIMode)
}
\ No newline at end of file
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt
index 963d0ab92d..8a60dec354 100644
--- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt
@@ -3,6 +3,7 @@ package com.tangem.feature.swap.domain.di
import com.tangem.feature.swap.domain.AllowPermissionsHandler
import com.tangem.feature.swap.domain.AllowPermissionsHandlerImpl
import com.tangem.feature.swap.domain.GetSwapUiModeUseCase
+import com.tangem.feature.swap.domain.SetSwapUiModeUseCase
import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.feature.swap.domain.SwapInteractorImpl
import com.tangem.feature.swap.domain.api.SwapRepository
@@ -35,6 +36,11 @@ internal class SwapDomainModule {
swapFeatureToggles = swapFeatureToggles,
swapRepository = swapRepository,
)
+
+ @Provides
+ @Singleton
+ fun provideSetSwapUiModeUseCase(swapRepository: SwapRepository): SetSwapUiModeUseCase =
+ SetSwapUiModeUseCase(swapRepository = swapRepository)
}
@Module
diff --git a/features/swap/domain/src/test/kotlin/com/tangem/feature/swap/domain/SetSwapUiModeUseCaseTest.kt b/features/swap/domain/src/test/kotlin/com/tangem/feature/swap/domain/SetSwapUiModeUseCaseTest.kt
new file mode 100644
index 0000000000..97cca8f4c1
--- /dev/null
+++ b/features/swap/domain/src/test/kotlin/com/tangem/feature/swap/domain/SetSwapUiModeUseCaseTest.kt
@@ -0,0 +1,29 @@
+package com.tangem.feature.swap.domain
+
+import com.tangem.feature.swap.domain.api.SwapRepository
+import com.tangem.feature.swap.domain.models.domain.SwapUIMode
+import io.mockk.coVerify
+import io.mockk.mockk
+import kotlinx.coroutines.test.runTest
+import org.junit.jupiter.api.Test
+
+internal class SetSwapUiModeUseCaseTest {
+
+ private val swapRepository: SwapRepository = mockk(relaxUnitFun = true)
+
+ private val useCase = SetSwapUiModeUseCase(swapRepository = swapRepository)
+
+ @Test
+ fun `GIVEN Simple mode WHEN invoke THEN delegates to repository`() = runTest {
+ useCase.invoke(SwapUIMode.Simple)
+
+ coVerify(exactly = 1) { swapRepository.storeSwapUiMode(SwapUIMode.Simple) }
+ }
+
+ @Test
+ fun `GIVEN Detailed mode WHEN invoke THEN delegates to repository`() = runTest {
+ useCase.invoke(SwapUIMode.Detailed)
+
+ coVerify(exactly = 1) { swapRepository.storeSwapUiMode(SwapUIMode.Detailed) }
+ }
+}
\ No newline at end of file
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt
index 8f249d3085..d8f79e8f0d 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt
@@ -74,6 +74,7 @@ import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
import com.tangem.feature.swap.domain.AllowPermissionsHandler
import com.tangem.feature.swap.domain.GetSwapUiModeUseCase
+import com.tangem.feature.swap.domain.SetSwapUiModeUseCase
import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.feature.swap.domain.TransactionFeeResult
import com.tangem.feature.swap.domain.TxFeeSealedState
@@ -83,6 +84,7 @@ import com.tangem.feature.swap.domain.models.domain.ExchangeProviderType
import com.tangem.feature.swap.domain.models.domain.SwapDataModel
import com.tangem.feature.swap.domain.models.domain.SwapPairLeast
import com.tangem.feature.swap.domain.models.domain.SwapProvider
+import com.tangem.feature.swap.domain.models.domain.SwapUIMode
import com.tangem.feature.swap.domain.models.ui.*
import com.tangem.feature.swap.domain.transfer.SwapTransferInteractor
import com.tangem.feature.swap.models.*
@@ -157,6 +159,7 @@ internal class SwapModel @Inject constructor(
private val allowPermissionsHandler: AllowPermissionsHandler,
private val swapFeatureToggles: SwapFeatureToggles,
private val getSwapUiModeUseCase: GetSwapUiModeUseCase,
+ private val setSwapUiModeUseCase: SetSwapUiModeUseCase,
) : Model() {
private val params = paramsContainer.require()
@@ -192,6 +195,7 @@ internal class SwapModel @Inject constructor(
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
isAccountsModeProvider = Provider { isAccountsMode },
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
+ shouldShowAbMenu = swapFeatureToggles.isSwapAbEnabled,
)
private val inputNumberFormatter = InputNumberFormatter(
@@ -1621,9 +1625,16 @@ internal class SwapModel @Inject constructor(
onSuccess = {
router.replaceAll(SwapRoute.Success)
},
+ onSwapUIModeChange = ::onSwapUIModeChange,
)
}
+ private fun onSwapUIModeChange(mode: SwapUIMode) {
+ if (uiState.swapUIMode == mode) return
+ uiState = uiState.copy(swapUIMode = mode)
+ modelScope.launch { setSwapUiModeUseCase(mode) }
+ }
+
private fun selectWalletInSelector(
fromSwapCurrencyStatus: SwapCurrencyStatus?,
toSwapCurrencyStatus: SwapCurrencyStatus?,
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt
index d96f1afc23..aba41ecb33 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt
@@ -33,6 +33,7 @@ internal data class SwapStateHolder(
val shouldShowMaxAmount: Boolean,
val tosState: TosState? = null,
val swapUIMode: SwapUIMode = SwapUIMode.Detailed,
+ val shouldShowAbMenu: Boolean = false,
val onRefresh: () -> Unit,
val onBackClicked: () -> Unit,
@@ -41,6 +42,7 @@ internal data class SwapStateHolder(
val onSuccess: (() -> Unit),
val onMaxAmountSelected: (() -> Unit)? = null,
val onShowPermissionBottomSheet: () -> Unit = {},
+ val onSwapUIModeChange: (SwapUIMode) -> Unit = {},
)
@Immutable
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/models/UiActions.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/models/UiActions.kt
index f9f2353886..31ccca8739 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/models/UiActions.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/models/UiActions.kt
@@ -1,6 +1,7 @@
package com.tangem.feature.swap.models
import com.tangem.feature.swap.domain.models.SwapAmount
+import com.tangem.feature.swap.domain.models.domain.SwapUIMode
import com.tangem.feature.swap.domain.models.ui.TxFee
import java.math.BigDecimal
@@ -26,4 +27,5 @@ internal data class UiActions(
val onSuccess: () -> Unit,
val onLinkClick: (String) -> Unit,
val onReceiveCardWarningClick: () -> Unit,
+ val onSwapUIModeChange: (SwapUIMode) -> Unit,
)
\ No newline at end of file
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ProviderItemSimple.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ProviderItemSimple.kt
new file mode 100644
index 0000000000..71cd53b67e
--- /dev/null
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/ProviderItemSimple.kt
@@ -0,0 +1,156 @@
+package com.tangem.feature.swap.ui
+
+import android.content.res.Configuration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import coil.compose.SubcomposeAsyncImage
+import coil.request.ImageRequest
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.RectangleShimmer
+import com.tangem.core.ui.components.SpacerW8
+import com.tangem.core.ui.components.SpacerWMax
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.core.ui.extensions.stringResourceSafe
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.feature.swap.models.states.PercentDifference
+import com.tangem.feature.swap.models.states.ProviderState
+
+// TODO: [REDACTED_TASK_KEY] — remove this UI after swap migrates to swap-v2.
+// Layout copied from V2 `SwapChooseProviderContent`:
+// features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/SwapChooseProviderContent.kt
+@Composable
+internal fun ProviderItemBlockSimple(state: ProviderState, modifier: Modifier = Modifier) {
+ if (state is ProviderState.Empty) return
+
+ Row(
+ modifier = modifier
+ .clip(RoundedCornerShape(TangemTheme.dimens.radius16))
+ .background(TangemTheme.colors.background.primary)
+ .clickable(
+ enabled = state.onProviderClick != null,
+ onClick = { state.onProviderClick?.invoke(state.id) },
+ )
+ .fillMaxWidth()
+ .padding(TangemTheme.dimens.spacing12),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_stack_new_24),
+ tint = TangemTheme.colors.icon.accent,
+ contentDescription = null,
+ modifier = Modifier.size(TangemTheme.dimens.size24),
+ )
+ SpacerW8()
+ Text(
+ text = stringResourceSafe(R.string.express_provider),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.primary1,
+ )
+ SpacerWMax()
+ SimpleProviderTrailing(state = state)
+ }
+}
+
+@Composable
+private fun SimpleProviderTrailing(state: ProviderState) {
+ when (state) {
+ is ProviderState.Content -> {
+ SubcomposeAsyncImage(
+ model = ImageRequest.Builder(context = LocalContext.current)
+ .data(state.iconUrl)
+ .crossfade(enable = true)
+ .allowHardware(false)
+ .build(),
+ loading = { RectangleShimmer(radius = 4.dp) },
+ error = { RectangleShimmer(radius = 4.dp) },
+ contentDescription = null,
+ modifier = Modifier
+ .size(TangemTheme.dimens.size20)
+ .clip(RoundedCornerShape(TangemTheme.dimens.radius4)),
+ )
+ Text(
+ text = state.name,
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.tertiary,
+ modifier = Modifier.padding(start = TangemTheme.dimens.spacing6),
+ )
+ Icon(
+ painter = painterResource(id = R.drawable.ic_chevron_24),
+ tint = TangemTheme.colors.icon.secondary,
+ contentDescription = null,
+ modifier = Modifier.size(TangemTheme.dimens.size24),
+ )
+ }
+ is ProviderState.Loading -> {
+ RectangleShimmer(
+ modifier = Modifier
+ .size(width = TangemTheme.dimens.size80, height = TangemTheme.dimens.size20),
+ radius = TangemTheme.dimens.radius4,
+ )
+ }
+ is ProviderState.Unavailable -> {
+ Text(
+ text = state.alertText.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.warning,
+ )
+ }
+ is ProviderState.Empty -> Unit
+ }
+}
+
+// region Preview
+@Preview(showBackground = true, widthDp = 360)
+@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun ProviderItemBlockSimple_Preview(@PreviewParameter(SimpleProviderPreview::class) state: ProviderState) {
+ TangemThemePreview {
+ ProviderItemBlockSimple(state = state)
+ }
+}
+
+private class SimpleProviderPreview : PreviewParameterProvider {
+ override val values: Sequence = sequenceOf(
+ ProviderState.Content(
+ id = "1",
+ name = "Changelly",
+ type = "CEX",
+ iconUrl = "",
+ subtitle = stringReference("1 SOL ≈ 0.0011337 BTC"),
+ selectionType = ProviderState.SelectionType.CLICK,
+ additionalBadge = ProviderState.AdditionalBadge.Empty,
+ percentLowerThenBest = PercentDifference.Empty,
+ namePrefix = ProviderState.PrefixType.NONE,
+ onProviderClick = {},
+ ),
+ ProviderState.Loading(),
+ ProviderState.Unavailable(
+ id = "2",
+ name = "1inch",
+ type = "DEX",
+ iconUrl = "",
+ alertText = stringReference("Unavailable"),
+ selectionType = ProviderState.SelectionType.NONE,
+ ),
+ )
+}
+// endregion
\ No newline at end of file
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt
index fe6ade5424..c2684c811a 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt
@@ -59,6 +59,7 @@ internal class StateBuilder(
private val appCurrencyProvider: Provider,
private val isAccountsModeProvider: Provider,
private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork,
+ private val shouldShowAbMenu: Boolean,
) {
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
@@ -97,6 +98,8 @@ internal class StateBuilder(
priceImpact = PriceImpact.Empty,
isInsufficientFunds = false,
swapUIMode = swapUIMode,
+ onSwapUIModeChange = actions.onSwapUIModeChange,
+ shouldShowAbMenu = shouldShowAbMenu,
)
}
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt
index 593a6e4109..4cc5d10cd9 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt
@@ -2,19 +2,39 @@ package com.tangem.feature.swap.ui
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+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.systemBarsPadding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
-import com.tangem.core.ui.components.appbar.AppBarWithBackButton
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
+import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.SwapTokenScreenTestTags
import com.tangem.core.ui.utils.WindowInsetsZero
import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
+import com.tangem.feature.swap.domain.models.domain.SwapUIMode
import com.tangem.feature.swap.models.SwapStateHolder
import com.tangem.feature.swap.models.states.ChooseFeeBottomSheetConfig
import com.tangem.feature.swap.models.states.ChooseProviderBottomSheetConfig
@@ -26,13 +46,7 @@ internal fun SwapScreen(stateHolder: SwapStateHolder, feeSelectorBlockComponent:
Scaffold(
modifier = Modifier.systemBarsPadding(),
- topBar = {
- AppBarWithBackButton(
- text = stringResourceSafe(R.string.common_swap),
- onBackClick = stateHolder.onBackClicked,
- iconRes = R.drawable.ic_close_24,
- )
- },
+ topBar = { SwapTopBar(stateHolder = stateHolder) },
contentWindowInsets = WindowInsetsZero,
containerColor = TangemTheme.colors.background.secondary,
) { scaffoldPaddings ->
@@ -64,4 +78,79 @@ internal fun SwapScreen(stateHolder: SwapStateHolder, feeSelectorBlockComponent:
}
}
}
+}
+
+@Composable
+private fun SwapTopBar(stateHolder: SwapStateHolder) {
+ var shouldShowModeMenu by rememberSaveable { mutableStateOf(false) }
+ Box(modifier = Modifier.fillMaxWidth()) {
+ AppBarWithBackButtonAndIcon(
+ text = stringResourceSafe(R.string.common_swap),
+ backIconRes = R.drawable.ic_close_24,
+ iconRes = if (stateHolder.shouldShowAbMenu) R.drawable.ic_more_vertical_24 else null,
+ onIconClick = if (stateHolder.shouldShowAbMenu) {
+ { shouldShowModeMenu = true }
+ } else {
+ null
+ },
+ onBackClick = stateHolder.onBackClicked,
+ )
+ if (stateHolder.shouldShowAbMenu) {
+ Box(modifier = Modifier.align(Alignment.TopEnd)) {
+ TangemDropdownMenu(
+ expanded = shouldShowModeMenu,
+ modifier = Modifier.background(TangemTheme.colors.background.primary),
+ offset = DpOffset(x = TangemTheme.dimens.spacing20, y = 44.dp),
+ onDismissRequest = { shouldShowModeMenu = false },
+ content = {
+ SwapUiModeMenuItem(
+ title = stringResourceSafe(R.string.swap_simple_mode),
+ isSelected = stateHolder.swapUIMode == SwapUIMode.Simple,
+ onClick = {
+ shouldShowModeMenu = false
+ stateHolder.onSwapUIModeChange(SwapUIMode.Simple)
+ },
+ )
+ SwapUiModeMenuItem(
+ title = stringResourceSafe(R.string.swap_detailed_mode),
+ isSelected = stateHolder.swapUIMode == SwapUIMode.Detailed,
+ onClick = {
+ shouldShowModeMenu = false
+ stateHolder.onSwapUIModeChange(SwapUIMode.Detailed)
+ },
+ )
+ },
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun SwapUiModeMenuItem(title: String, isSelected: Boolean, onClick: () -> Unit) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable(onClick = onClick)
+ .padding(horizontal = 16.dp, vertical = 8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ ) {
+ Text(
+ text = title,
+ style = TangemTheme.typography.button,
+ color = TangemTheme.colors.text.primary1,
+ modifier = Modifier.weight(1f),
+ )
+ if (isSelected) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_check_24),
+ tint = TangemTheme.colors.icon.primary1,
+ contentDescription = null,
+ modifier = Modifier.size(16.dp),
+ )
+ } else {
+ Spacer(modifier = Modifier.width(16.dp))
+ }
+ }
}
\ No newline at end of file
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt
index b8006f40bb..fa11d144da 100644
--- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt
@@ -39,6 +39,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.SwapTokenScreenTestTags
+import com.tangem.feature.swap.domain.models.domain.SwapUIMode
import com.tangem.feature.swap.domain.models.ui.FeeType
import com.tangem.feature.swap.domain.models.ui.PriceImpact
import com.tangem.feature.swap.models.*
@@ -79,7 +80,11 @@ internal fun SwapScreenContent(
) {
MainInfo(state)
- ProviderItemBlock(state = state.providerState)
+ if (state.swapUIMode == SwapUIMode.Simple) {
+ ProviderItemBlockSimple(state = state.providerState)
+ } else {
+ ProviderItemBlock(state = state.providerState)
+ }
if (feeBlock != null) {
feeBlock(Modifier.fillMaxWidth())
@@ -139,14 +144,25 @@ private fun MainInfo(state: SwapStateHolder) {
onSelectTokenClick = { state.onSelectTokenClick(TokenSelectionDirection.FROM) },
)
val marginCard = TangemTheme.dimens.spacing12
- TransactionCard(
- priceImpact = priceImpact,
- swapCardState = state.receiveCardData,
- modifier = Modifier.constrainAs(bottomCard) {
- top.linkTo(topCard.bottom, margin = marginCard)
- },
- onSelectTokenClick = { state.onSelectTokenClick(TokenSelectionDirection.TO) },
- )
+ if (state.swapUIMode == SwapUIMode.Simple) {
+ TransactionCardSimple(
+ priceImpact = priceImpact,
+ swapCardState = state.receiveCardData,
+ modifier = Modifier.constrainAs(bottomCard) {
+ top.linkTo(topCard.bottom, margin = marginCard)
+ },
+ onSelectTokenClick = { state.onSelectTokenClick(TokenSelectionDirection.TO) },
+ )
+ } else {
+ TransactionCard(
+ priceImpact = priceImpact,
+ swapCardState = state.receiveCardData,
+ modifier = Modifier.constrainAs(bottomCard) {
+ top.linkTo(topCard.bottom, margin = marginCard)
+ },
+ onSelectTokenClick = { state.onSelectTokenClick(TokenSelectionDirection.TO) },
+ )
+ }
val marginButton = TangemTheme.dimens.spacing30
SwapButton(
state,
diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCardSimple.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCardSimple.kt
new file mode 100644
index 0000000000..a807f078a3
--- /dev/null
+++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/TransactionCardSimple.kt
@@ -0,0 +1,418 @@
+package com.tangem.feature.swap.ui
+
+import android.content.res.Configuration
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.TextAutoSize
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.material3.ripple
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.tangem.common.ui.account.AccountTitle
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.RectangleShimmer
+import com.tangem.core.ui.components.SpacerH4
+import com.tangem.core.ui.components.SpacerW16
+import com.tangem.core.ui.components.TextShimmer
+import com.tangem.core.ui.components.buttons.SecondarySmallButton
+import com.tangem.core.ui.components.buttons.SmallButtonConfig
+import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
+import com.tangem.core.ui.extensions.orMaskWithStars
+import com.tangem.core.ui.extensions.resolveAnnotatedReference
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringResourceSafe
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.core.ui.test.SwapTokenScreenTestTags
+import com.tangem.feature.swap.domain.models.ui.PriceImpact
+import com.tangem.feature.swap.models.SwapCardState
+import com.tangem.feature.swap.models.TransactionCardType
+import com.tangem.feature.swap.ui.preview.SwapTransactionCardPreview
+
+@Composable
+internal fun TransactionCardSimple(
+ priceImpact: PriceImpact,
+ swapCardState: SwapCardState,
+ onSelectTokenClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ val cardTag = when (swapCardState.type) {
+ is TransactionCardType.Inputtable -> SwapTokenScreenTestTags.SWAP_CARD
+ is TransactionCardType.ReadOnly -> SwapTokenScreenTestTags.RECEIVE_CARD
+ }
+
+ when (swapCardState) {
+ is SwapCardState.Empty -> SimpleTransactionCardEmpty(
+ cardState = swapCardState,
+ onChangeTokenClick = onSelectTokenClick,
+ modifier = modifier.testTag(cardTag),
+ )
+ is SwapCardState.SwapCardData -> SimpleTransactionCardData(
+ cardState = swapCardState,
+ priceImpact = priceImpact,
+ onChangeTokenClick = onSelectTokenClick,
+ modifier = modifier.testTag(cardTag),
+ )
+ is SwapCardState.Loading -> SimpleTransactionCardLoading(modifier = modifier.testTag(cardTag))
+ }
+}
+
+@Composable
+private fun SimpleTransactionCardData(
+ cardState: SwapCardState.SwapCardData,
+ priceImpact: PriceImpact,
+ modifier: Modifier = Modifier,
+ onChangeTokenClick: (() -> Unit)? = null,
+) {
+ Box(
+ modifier = modifier
+ .background(
+ shape = RoundedCornerShape(TangemTheme.dimens.radius16),
+ color = TangemTheme.colors.background.primary,
+ )
+ .fillMaxWidth(),
+ ) {
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ verticalArrangement = Arrangement.Top,
+ horizontalAlignment = Alignment.Start,
+ ) {
+ SimpleHeader(
+ balance = stringResourceSafe(
+ R.string.common_balance,
+ cardState.balance,
+ ).orMaskWithStars(cardState.isBalanceHidden),
+ type = cardState.type,
+ )
+
+ SimpleContent(
+ type = cardState.type,
+ textFieldValue = cardState.amountTextFieldValue,
+ priceImpact = priceImpact,
+ )
+ }
+
+ Box(modifier = Modifier.align(Alignment.BottomEnd)) {
+ Token(
+ currencyIconState = cardState.currencyIconState,
+ tokenSymbol = cardState.tokenSymbol,
+ )
+ }
+
+ if (onChangeTokenClick != null) {
+ Box(modifier = Modifier.align(Alignment.CenterEnd)) {
+ ChangeTokenSelector()
+ }
+ Box(
+ Modifier
+ .align(Alignment.CenterEnd)
+ .height(TangemTheme.dimens.size116)
+ .width(TangemTheme.dimens.size102)
+ .clickable(
+ indication = ripple(bounded = false),
+ interactionSource = remember { MutableInteractionSource() },
+ ) { onChangeTokenClick() },
+ )
+ }
+ }
+}
+
+@Composable
+private fun SimpleTransactionCardEmpty(
+ cardState: SwapCardState.Empty,
+ modifier: Modifier = Modifier,
+ onChangeTokenClick: () -> Unit,
+) {
+ Column(
+ modifier = modifier
+ .background(
+ shape = RoundedCornerShape(TangemTheme.dimens.radius12),
+ color = TangemTheme.colors.background.primary,
+ )
+ .padding(
+ top = 12.dp,
+ start = 12.dp,
+ end = 12.dp,
+ bottom = 16.dp,
+ )
+ .fillMaxWidth(),
+ horizontalAlignment = Alignment.Start,
+ verticalArrangement = Arrangement.spacedBy(6.dp),
+ ) {
+ AccountTitle(
+ accountTitleUM = cardState.type.accountTitleUM,
+ modifier = Modifier.fillMaxWidth(),
+ )
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Column(
+ modifier = Modifier.weight(1f),
+ verticalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Text(
+ text = cardState.amountTextFieldValue?.text.orEmpty(),
+ color = TangemTheme.colors.text.disabled,
+ style = TangemTheme.typography.h2,
+ autoSize = TextAutoSize.StepBased(
+ minFontSize = 16.sp,
+ maxFontSize = TangemTheme.typography.h2.fontSize,
+ ),
+ maxLines = 1,
+ modifier = Modifier.testTag(SwapTokenScreenTestTags.SWAP_TEXT_FIELD),
+ )
+ Text(
+ text = cardState.amountEquivalent.resolveAnnotatedReference(),
+ color = TangemTheme.colors.text.tertiary,
+ style = TangemTheme.typography.body2,
+ modifier = Modifier
+ .defaultMinSize(minHeight = TangemTheme.dimens.size20)
+ .testTag(SwapTokenScreenTestTags.SWAP_FIAT_AMOUNT),
+ )
+ }
+ SecondarySmallButton(
+ config = SmallButtonConfig(
+ text = resourceReference(R.string.common_choose_token),
+ icon = TangemButtonIconPosition.End(R.drawable.ic_chevron_24),
+ onClick = onChangeTokenClick,
+ ),
+ )
+ }
+ }
+}
+
+@Composable
+private fun SimpleTransactionCardLoading(modifier: Modifier = Modifier) {
+ Column(
+ modifier = modifier
+ .background(
+ shape = RoundedCornerShape(TangemTheme.dimens.radius12),
+ color = TangemTheme.colors.background.primary,
+ )
+ .padding(
+ top = 12.dp,
+ start = 12.dp,
+ end = 12.dp,
+ bottom = 16.dp,
+ )
+ .fillMaxWidth(),
+ horizontalAlignment = Alignment.Start,
+ verticalArrangement = Arrangement.spacedBy(6.dp),
+ ) {
+ Column(modifier = Modifier.fillMaxWidth()) {
+ TextShimmer(
+ text = stringResourceSafe(R.string.swapping_to_title),
+ style = TangemTheme.typography.subtitle2,
+ )
+ TextShimmer(
+ style = TangemTheme.typography.body2,
+ modifier = Modifier
+ .testTag(SwapTokenScreenTestTags.BALANCE)
+ .width(60.dp),
+ )
+ }
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Column(
+ modifier = Modifier.weight(1f),
+ verticalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ TextShimmer(
+ style = TangemTheme.typography.h2,
+ modifier = Modifier
+ .width(100.dp)
+ .testTag(SwapTokenScreenTestTags.SWAP_TEXT_FIELD),
+ )
+ TextShimmer(
+ style = TangemTheme.typography.body2,
+ modifier = Modifier
+ .defaultMinSize(minHeight = 20.dp, minWidth = 40.dp)
+ .testTag(SwapTokenScreenTestTags.SWAP_FIAT_AMOUNT),
+ )
+ }
+ SecondarySmallButton(
+ config = SmallButtonConfig(
+ text = resourceReference(R.string.common_choose_token),
+ icon = TangemButtonIconPosition.End(R.drawable.ic_chevron_24),
+ isEnabled = false,
+ onClick = {},
+ ),
+ )
+ }
+ }
+}
+
+@Composable
+private fun SimpleHeader(type: TransactionCardType, balance: String, modifier: Modifier = Modifier) {
+ Column(
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(
+ bottom = TangemTheme.dimens.spacing8,
+ top = TangemTheme.dimens.spacing14,
+ start = TangemTheme.dimens.spacing12,
+ end = TangemTheme.dimens.spacing12,
+ )
+ .testTag(SwapTokenScreenTestTags.SWAP_BLOCK_HEADER),
+ ) {
+ val titleColor = if (type.inputError is TransactionCardType.InputError.Empty) {
+ TangemTheme.colors.text.tertiary
+ } else {
+ TangemTheme.colors.text.warning
+ }
+ AccountTitle(
+ accountTitleUM = type.accountTitleUM,
+ textColor = titleColor,
+ )
+ SpacerW16()
+ if (balance.isNotBlank()) {
+ AnimatedContent(targetState = balance, label = "") { balanceText ->
+ Text(
+ text = balanceText,
+ color = TangemTheme.colors.text.tertiary,
+ style = TangemTheme.typography.body2,
+ modifier = Modifier.testTag(SwapTokenScreenTestTags.BALANCE),
+ )
+ }
+ } else {
+ RectangleShimmer(
+ modifier = Modifier
+ .width(TangemTheme.dimens.size80)
+ .height(TangemTheme.dimens.size12),
+ radius = TangemTheme.dimens.radius3,
+ )
+ }
+ }
+}
+
+@Suppress("LongMethod")
+@Composable
+private fun SimpleContent(type: TransactionCardType, priceImpact: PriceImpact, textFieldValue: TextFieldValue?) {
+ Row(
+ modifier = Modifier
+ .padding(
+ start = TangemTheme.dimens.spacing12,
+ bottom = TangemTheme.dimens.spacing16,
+ ),
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.Top,
+ ) {
+ Column(
+ modifier = Modifier.padding(end = TangemTheme.dimens.spacing92),
+ verticalArrangement = Arrangement.Top,
+ horizontalAlignment = Alignment.Start,
+ ) {
+ val sumTextModifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size32)
+ when (type) {
+ is TransactionCardType.ReadOnly -> {
+ if (textFieldValue != null) {
+ Text(
+ text = textFieldValue.text,
+ color = TangemTheme.colors.text.primary1,
+ style = TangemTheme.typography.h2,
+ autoSize = TextAutoSize.StepBased(
+ minFontSize = 16.sp,
+ maxFontSize = TangemTheme.typography.h2.fontSize,
+ ),
+ maxLines = 1,
+ modifier = sumTextModifier.testTag(SwapTokenScreenTestTags.RECEIVE_TEXT_FIELD),
+ )
+ } else {
+ RectangleShimmer(
+ modifier = Modifier
+ .padding(vertical = TangemTheme.dimens.spacing4)
+ .width(TangemTheme.dimens.size102)
+ .height(TangemTheme.dimens.size24),
+ )
+ }
+ }
+ is TransactionCardType.Inputtable -> {
+ val focusRequester = remember { FocusRequester() }
+ AutoSizeTextField(
+ modifier = sumTextModifier.testTag(SwapTokenScreenTestTags.SWAP_TEXT_FIELD),
+ focusRequester = focusRequester,
+ textFieldValue = textFieldValue ?: TextFieldValue(),
+ isEnabled = type.isEnabled,
+ onAmountChange = { type.onAmountChanged(it) },
+ onFocusChange = type.onFocusChanged,
+ )
+ LaunchedEffect(Unit) { focusRequester.requestFocus() }
+ }
+ }
+ SpacerH4()
+ // Keep the same 20dp slot as Detailed (where fiat/shimmer lives)
+ // so that Token (BottomEnd) does not shift when switching modes.
+ Box(modifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size20)) {
+ if (type is TransactionCardType.ReadOnly && type.shouldShowWarning) {
+ WarningIcon(priceImpact = priceImpact, onClick = type.onWarningClick)
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun WarningIcon(priceImpact: PriceImpact, onClick: (() -> Unit)?) {
+ IconButton(
+ onClick = { onClick?.invoke() },
+ modifier = Modifier.size(TangemTheme.dimens.size20),
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_information_24),
+ contentDescription = null,
+ tint = when (priceImpact.type) {
+ PriceImpact.Type.HIGH -> TangemTheme.colors.text.warning
+ PriceImpact.Type.MEDIUM -> TangemTheme.colors.text.attention
+ else -> TangemTheme.colors.text.tertiary
+ },
+ modifier = Modifier.testTag(SwapTokenScreenTestTags.RECEIVE_FIAT_AMOUNT_INFORMATION_ICON),
+ )
+ }
+}
+
+// region Preview
+@Preview(showBackground = true, widthDp = 360)
+@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun TransactionCardSimple_Preview(@PreviewParameter(SimplePreviewProvider::class) params: SwapCardState) {
+ TangemThemePreview {
+ TransactionCardSimple(
+ priceImpact = PriceImpact.Empty,
+ swapCardState = params,
+ onSelectTokenClick = {},
+ modifier = Modifier,
+ )
+ }
+}
+
+private class SimplePreviewProvider : PreviewParameterProvider {
+ override val values: Sequence = sequenceOf(
+ SwapTransactionCardPreview.sendCard,
+ SwapTransactionCardPreview.receiveCard,
+ SwapTransactionCardPreview.emptyReadOnlyCard,
+ SwapTransactionCardPreview.emptyInputtableCard,
+ SwapTransactionCardPreview.loadingCard,
+ )
+}
+// endregion
\ No newline at end of file
diff --git a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderInitialStateTest.kt b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderInitialStateTest.kt
index 74d5f2bf6b..cd31b0db91 100644
--- a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderInitialStateTest.kt
+++ b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderInitialStateTest.kt
@@ -48,6 +48,7 @@ internal class StateBuilderInitialStateTest {
appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
+ shouldShowAbMenu = false,
)
}
diff --git a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderPairsTest.kt b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderPairsTest.kt
index ef0ac3d90e..3045de86cd 100644
--- a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderPairsTest.kt
+++ b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderPairsTest.kt
@@ -53,6 +53,7 @@ internal class StateBuilderPairsTest {
appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
+ shouldShowAbMenu = false,
)
}
diff --git a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderQuotesTest.kt b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderQuotesTest.kt
index 0302eebdfc..e03feca1b0 100644
--- a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderQuotesTest.kt
+++ b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderQuotesTest.kt
@@ -57,6 +57,7 @@ internal class StateBuilderQuotesTest {
appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
+ shouldShowAbMenu = false,
)
}
diff --git a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderSwapDataTest.kt b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderSwapDataTest.kt
index 2d15fe9295..7d74bddb02 100644
--- a/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderSwapDataTest.kt
+++ b/features/swap/impl/src/test/java/com/tangem/feature/swap/StateBuilderSwapDataTest.kt
@@ -59,6 +59,7 @@ internal class StateBuilderSwapDataTest {
appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
+ shouldShowAbMenu = false,
)
}