diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml
index 8278e828ad..36b3355615 100644
--- a/core/res/src/main/res/values-es/strings.xml
+++ b/core/res/src/main/res/values-es/strings.xml
@@ -979,6 +979,7 @@
Porcentaje de rendimiento anual
El porcentaje de rendimiento anual que podrá ganar como participante en el staking.
APR
+ APY
Las recompensas se acumulan automáticamente en su saldo de staking diariamente.
Disponible
Tasa de recompensa promedio
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index b4299c0887..47bac750bc 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -160,7 +160,7 @@
Activer
Activé
Erreur
- Échangez
+ Echanger
Explorez
Explorez l\'historique des transactions
Explorateur
@@ -953,6 +953,7 @@
Pourcentage de rendement annuel
Le pourcentage de rendement annuel que vous pouvez gagner en participant au staking.
APR
+ APY
Les récompenses s\'accumulent automatiquement sur votre solde de staking quotidiennement.
Disponible
Taux de récompense moyen
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index bd9bd6be0d..48e34783ae 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -911,6 +911,7 @@
このアドレスには%sのみを送金してください。他のトークンを送信すると、取り返しのつかない損失が発生します。
%2$sネットワークの%1$sのみを送信してください
ウォレットや取引所から資金を送金する
+ 報酬の送付先アドレス
参加する
紹介プログラムに関する情報を読み込めませんでした。しばらくしてからもう一度お試しください。
紹介プログラムに関する情報を読み込めませんでした。エラー コード: %s 。しばらくしてからもう一度お試しください。
@@ -1094,6 +1095,7 @@
年率
ステーキングに参加することで得られる年間収益率。
APR
+ APY
報酬は毎日自動的にステーキング残高に蓄積されます。
利用可能
平均報酬率
@@ -1391,8 +1393,8 @@
Tangemアプリで誤ったカードまたはリングが選択されました
Dappデータから取引を作成できませんでした。コード: %s
不明なエラーが発生しました。エラーコード: %d 。問題が解決しない場合は、お気軽にサポートにお問い合わせください。
- 複数の取引
- このプロセスを完了するには、Tangemデバイスを数回タップする必要があります。
+ マルチパート取引
+ 正常に処理するため、取引は複数に分割されます。完了するにはカードを数回タップする必要があります。
WalletConnectセッションが開かれていません
おっと。セッションがありません。
WalletConnectセッションのペアリングに失敗しました: %1$s
@@ -1404,8 +1406,8 @@
このカードは、WalletConnectセッションの確立には使用できません。
このネットワークはサポートされていません。別のネットワークを選択してください。
ネットワークを選択
- 取引を処理中です
- 送金しています...
+ 取引を処理中です。完了するにはカードを複数回タップしてください。
+ 取引進行中
WalletConnectセッション
dAppsに接続する
WalletConnect
@@ -1659,6 +1661,7 @@
承認を確定する
資産残高に関するテキスト [プレースホルダー]
あなたの%sはAaveに預けられています
+ 受け取った金額%1$s %2$sはAaveに入金されませんでした。
%1$s%% を獲得
利用可能
現在のAPY
@@ -1674,6 +1677,7 @@
ネットワーク手数料が上限手数料を超えた場合、手数料が下がるまで取引は成立しません。この制限は後で変更できます。
最大手数料
手数料ポリシー
+ ネットワーク手数料が現在高すぎます。設定した上限を下回るまで待機しています。
ここに説明を入力してください。1〜3行が理想的です。[プレースホルダー]
トークン承認が必要
ネットワーク接続を確認してください
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 979bd1a061..47b4f344fa 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -1043,6 +1043,7 @@
Процентная ставка
Годовой процентный доход, который вы можете получить от участия в стейкинге.
APR
+ APY
Награда автоматически аккумулируется на вашем стейкинг балансе.
Доступно
Средння ставка вознаграждения
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 90e59315d2..6946a0d572 100644
--- a/core/res/src/main/res/values-uk-rUA/strings.xml
+++ b/core/res/src/main/res/values-uk-rUA/strings.xml
@@ -959,6 +959,7 @@
Процентна ставка
Річний відсоток, який ви можете отримати, беручи участь у стейкінгу.
APR
+ APY
Винагороди автоматично накопичуються на вашому балансі щодня.
Доступно
Середня ставка винагороди
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 376b83e07c..94d0e6a553 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -33,6 +33,7 @@
Add account
Save
Account name
+ Account name already exists
Account
New account
Add account
@@ -905,6 +906,7 @@
%s min
You get
+ Service is provided by an external provider. \nTangem is not responsible.
You can close this screen and check the transaction status on the token details screen.
Up to
Via
@@ -1116,7 +1118,10 @@
A staking account is a special account where staked SOL tokens are stored. It is created when you delegate your tokens to a validator to participate in transaction validation and receive rewards. A small fee is charged for creating the staking account, which is returned after the staking is completed.
Annual percentage rate
The annual percentage return you can earn from participating in staking.
+ Annual percentage yield
+ APY shows the validator’s annual percentage yield based on its performance
APR
+ APY
Rewards automatically accumulate in your staking balance daily.
Available
Average Reward Rate
@@ -1314,6 +1319,7 @@
Token in %%image%% %1$s network
The %1$s (%2$s) token is the main currency on the %3$s network and cannot be hidden as long as you have other tokens on this network in the list
Unable to hide %s
+ Show QR code
Exchange this token for another at %1$s service fees from February %2$s-%3$s.
Swap with Changelly, %s fees
Swap now
@@ -1788,4 +1794,5 @@
Unable to cover %s fee
The interest service isn’t available at the moment. Please try again later.
Earnings unavailable
+ Unable to load chart...
diff --git a/domain/account/src/main/java/com/tangem/domain/account/models/AccountList.kt b/domain/account/src/main/java/com/tangem/domain/account/models/AccountList.kt
index c81e865d8e..2f848f2f16 100644
--- a/domain/account/src/main/java/com/tangem/domain/account/models/AccountList.kt
+++ b/domain/account/src/main/java/com/tangem/domain/account/models/AccountList.kt
@@ -127,7 +127,7 @@ data class AccountList private constructor(
companion object {
- private const val MAX_ACCOUNTS_COUNT = 20
+ const val MAX_ACCOUNTS_COUNT = 20
private const val MAX_MAIN_ACCOUNTS_COUNT = 1
/**
diff --git a/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/GetSelectedAppCurrencyUseCase.kt b/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/GetSelectedAppCurrencyUseCase.kt
index 179973c048..9defeeadae 100644
--- a/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/GetSelectedAppCurrencyUseCase.kt
+++ b/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/GetSelectedAppCurrencyUseCase.kt
@@ -1,6 +1,7 @@
package com.tangem.domain.appcurrency
import arrow.core.Either
+import arrow.core.getOrElse
import arrow.core.left
import arrow.core.right
import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError
@@ -19,6 +20,10 @@ class GetSelectedAppCurrencyUseCase(
.onEmpty { emit(SelectedAppCurrencyError.NoAppCurrencySelected.left()) }
}
+ fun invokeOrDefault(): Flow = invoke()
+ .map { it.getOrElse { AppCurrency.Default } }
+ .distinctUntilChanged()
+
suspend fun invokeSync(): Either {
return invoke().firstOrNull() ?: SelectedAppCurrencyError.NoAppCurrencySelected.left()
}
diff --git a/domain/balance-hiding/src/main/kotlin/com/tangem/domain/balancehiding/GetBalanceHidingSettingsUseCase.kt b/domain/balance-hiding/src/main/kotlin/com/tangem/domain/balancehiding/GetBalanceHidingSettingsUseCase.kt
index 6f4c08e5fa..bfd742292f 100644
--- a/domain/balance-hiding/src/main/kotlin/com/tangem/domain/balancehiding/GetBalanceHidingSettingsUseCase.kt
+++ b/domain/balance-hiding/src/main/kotlin/com/tangem/domain/balancehiding/GetBalanceHidingSettingsUseCase.kt
@@ -2,6 +2,8 @@ package com.tangem.domain.balancehiding
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
class GetBalanceHidingSettingsUseCase(
private val balanceHidingRepository: BalanceHidingRepository,
@@ -10,4 +12,8 @@ class GetBalanceHidingSettingsUseCase(
operator fun invoke(): Flow {
return balanceHidingRepository.getBalanceHidingSettingsFlow()
}
+
+ fun isBalanceHidden(): Flow = invoke()
+ .map { it.isBalanceHidden }
+ .distinctUntilChanged()
}
\ No newline at end of file
diff --git a/features/account/impl/src/main/java/com/tangem/features/account/createedit/AccountCreateEditModel.kt b/features/account/impl/src/main/java/com/tangem/features/account/createedit/AccountCreateEditModel.kt
index 8a050693bf..85d4b0d97f 100644
--- a/features/account/impl/src/main/java/com/tangem/features/account/createedit/AccountCreateEditModel.kt
+++ b/features/account/impl/src/main/java/com/tangem/features/account/createedit/AccountCreateEditModel.kt
@@ -78,10 +78,14 @@ internal class AccountCreateEditModel @Inject constructor(
isWarning = true,
onClick = { router.pop() },
)
+ val messageRes = when (params) {
+ is AccountCreateEditComponent.Params.Create -> R.string.account_unsaved_dialog_message_create
+ is AccountCreateEditComponent.Params.Edit -> R.string.account_unsaved_dialog_message_edit
+ }
messageSender.send(
DialogMessage(
title = resourceReference(R.string.account_unsaved_dialog_title),
- message = resourceReference(R.string.account_unsaved_dialog_message_create),
+ message = resourceReference(messageRes),
firstActionBuilder = { firstAction },
secondActionBuilder = { secondAction },
),
@@ -120,17 +124,15 @@ internal class AccountCreateEditModel @Inject constructor(
}
private fun handleAddAccountError(error: AddCryptoPortfolioUseCase.Error) {
- if (error is AddCryptoPortfolioUseCase.Error.AccountListRequirementsNotMet &&
- error.cause is AccountList.Error.DuplicateAccountNames
- ) {
- // TODO("account") show alert that the account name already exists
- return
+ val duplicateAccountNames = (error as? AddCryptoPortfolioUseCase.Error.AccountListRequirementsNotMet)
+ ?.cause is AccountList.Error.DuplicateAccountNames
+ when {
+ duplicateAccountNames -> showAccountNameExist()
+ else -> {
+ showSomethingWrong()
+ logError(error = AccountFeatureError.CreateAccount.FailedToCreateAccount(cause = error))
+ }
}
-
- // TODO: show alert https://www.figma.com/design/09KKG4ZVuFDZhj8WLv5rGJ/%F0%9F%9A%A7-App-experience?node-id=38882-113775&t=vk6TCy4MkYol1cPb-4
- logError(
- error = AccountFeatureError.CreateAccount.FailedToCreateAccount(cause = error),
- )
}
private suspend fun editCryptoPortfolio(params: AccountCreateEditComponent.Params.Edit) {
@@ -157,17 +159,15 @@ internal class AccountCreateEditModel @Inject constructor(
}
private fun handleEditAccountError(error: UpdateCryptoPortfolioUseCase.Error) {
- if (error is UpdateCryptoPortfolioUseCase.Error.AccountListRequirementsNotMet &&
- error.cause is AccountList.Error.DuplicateAccountNames
- ) {
- // TODO("account") show alert that the account name already exists
- return
+ val duplicateAccountNames = (error as? UpdateCryptoPortfolioUseCase.Error.AccountListRequirementsNotMet)
+ ?.cause is AccountList.Error.DuplicateAccountNames
+ when {
+ duplicateAccountNames -> showAccountNameExist()
+ else -> {
+ showSomethingWrong()
+ logError(error = AccountFeatureError.EditAccount.FailedToEditAccount(cause = error))
+ }
}
-
- // TODO: show alert like in create account flow
- logError(
- error = AccountFeatureError.EditAccount.FailedToEditAccount(cause = error),
- )
}
private fun showMessage(@StringRes id: Int) {
@@ -175,7 +175,10 @@ internal class AccountCreateEditModel @Inject constructor(
messageSender.send(ToastMessage(message = message))
}
- private fun onCloseClick() = unsaveChangeDialog()
+ private fun onCloseClick() {
+ val showConfirmDialog = uiState.value.buttonState.isButtonEnabled
+ if (showConfirmDialog) unsaveChangeDialog() else router.pop()
+ }
private fun onIconSelect(icon: CryptoPortfolioIcon.Icon) {
uiState.value = uiState.value
@@ -256,4 +259,20 @@ internal class AccountCreateEditModel @Inject constructor(
event = ExceptionAnalyticsEvent(exception = exception, params = params),
)
}
+
+ private fun showSomethingWrong() {
+ val dialogMessage = DialogMessage(
+ title = resourceReference(R.string.common_something_went_wrong),
+ message = resourceReference(R.string.account_could_not_create),
+ )
+ messageSender.send(dialogMessage)
+ }
+
+ private fun showAccountNameExist() {
+ val dialogMessage = DialogMessage(
+ title = resourceReference(R.string.common_something_went_wrong),
+ message = resourceReference(R.string.account_form_name_already_exist_error_description),
+ )
+ messageSender.send(dialogMessage)
+ }
}
\ No newline at end of file
diff --git a/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt b/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt
index 0e92bc9233..2c7168bc93 100644
--- a/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt
+++ b/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt
@@ -19,6 +19,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@@ -30,8 +32,8 @@ import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH24
import com.tangem.core.ui.components.SpacerH8
-import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.components.account.AccountIconSize
+import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.components.fields.AutoSizeTextField
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
@@ -43,9 +45,11 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
internal fun AccountCreateEditContent(state: AccountCreateEditUM, modifier: Modifier = Modifier) {
+ val keyboardController = LocalSoftwareKeyboardController.current
+ val focusManager = LocalFocusManager.current
Column(
modifier = modifier
- .background(color = TangemTheme.colors.background.tertiary)
+ .background(color = TangemTheme.colors.background.secondary)
.fillMaxSize()
.imePadding()
.systemBarsPadding(),
@@ -76,6 +80,10 @@ internal fun AccountCreateEditContent(state: AccountCreateEditUM, modifier: Modi
color = TangemTheme.colors.text.tertiary,
)
}
+ if (state.buttonState.showProgress) {
+ focusManager.clearFocus()
+ keyboardController?.hide()
+ }
PrimaryButton(
modifier = Modifier
.fillMaxWidth()
@@ -161,6 +169,7 @@ private fun AccountColor(colorsState: AccountCreateEditUM.Colors) {
contentAlignment = Alignment.Center,
modifier = Modifier
.wrapContentSize()
+ .clip(CircleShape)
.clickable(onClick = { colorsState.onColorSelect(color) })
.size(48.dp),
) {
@@ -208,6 +217,7 @@ private fun AccountIcons(iconsState: AccountCreateEditUM.Icons) {
contentAlignment = Alignment.Center,
modifier = Modifier
.wrapContentSize()
+ .clip(CircleShape)
.clickable(onClick = { iconsState.onIconSelect(icon) })
.size(52.dp),
) {
diff --git a/features/account/impl/src/main/java/com/tangem/features/account/fetcher/DefaultPortfolioFetcher.kt b/features/account/impl/src/main/java/com/tangem/features/account/fetcher/DefaultPortfolioFetcher.kt
index 4456993f0e..e1ae9bce5c 100644
--- a/features/account/impl/src/main/java/com/tangem/features/account/fetcher/DefaultPortfolioFetcher.kt
+++ b/features/account/impl/src/main/java/com/tangem/features/account/fetcher/DefaultPortfolioFetcher.kt
@@ -1,11 +1,9 @@
package com.tangem.features.account.fetcher
-import arrow.core.getOrElse
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
-import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
@@ -60,8 +58,8 @@ internal class DefaultPortfolioFetcher @AssistedInject constructor(
.map { it.filterWallets(mode) }
.distinctUntilChanged()
.flatMapLatest { wallets -> balancesForWallets(wallets) },
- flow2 = appCurrencyFlow(),
- flow3 = balanceHidingFlow(),
+ flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
+ flow3 = getBalanceHidingSettingsUseCase.isBalanceHidden(),
) { balances, appCurrency, isBalanceHiding ->
Data(
appCurrency = appCurrency,
@@ -94,18 +92,6 @@ internal class DefaultPortfolioFetcher @AssistedInject constructor(
private fun accountStatusListFlow(wallet: UserWallet): Flow =
singleAccountStatusListSupplier(SingleAccountStatusListProducer.Params(wallet.walletId))
- private fun appCurrencyFlow(): Flow {
- return getSelectedAppCurrencyUseCase()
- .map { it.getOrElse { AppCurrency.Default } }
- .distinctUntilChanged()
- }
-
- private fun balanceHidingFlow(): Flow {
- return getBalanceHidingSettingsUseCase()
- .map { it.isBalanceHidden }
- .distinctUntilChanged()
- }
-
@AssistedFactory
interface Factory : PortfolioFetcher.Factory {
override fun create(mode: Mode, scope: CoroutineScope): DefaultPortfolioFetcher
diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt
index 950000e443..ff72822f09 100644
--- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt
+++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt
@@ -1,8 +1,6 @@
package com.tangem.features.markets.portfolio.impl.loader
-import arrow.core.getOrElse
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
-import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.models.TotalFiatBalance
@@ -15,7 +13,6 @@ import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
import com.tangem.domain.tokens.error.TokenListError
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
-import timber.log.Timber
import javax.inject.Inject
/**
@@ -41,8 +38,8 @@ internal class PortfolioDataLoader @Inject constructor(
fun load(currencyRawId: CryptoCurrency.RawID): Flow {
return combine(
flow = getAllWalletsCryptoCurrenciesData(currencyRawId = currencyRawId),
- flow2 = getSelectedAppCurrencyFlow(),
- flow3 = getBalanceHidingSettingsFlow(),
+ flow2 = getSelectedAppCurrencyUseCase.invokeOrDefault(),
+ flow3 = getBalanceHidingSettingsUseCase.isBalanceHidden(),
) { walletsWithCurrencies, appCurrency, isBalanceHidden ->
PortfolioData(
walletsWithCurrencies = walletsWithCurrencies,
@@ -113,23 +110,6 @@ internal class PortfolioDataLoader @Inject constructor(
.distinctUntilChanged()
}
- private fun getSelectedAppCurrencyFlow(): Flow {
- return getSelectedAppCurrencyUseCase()
- .map {
- it.getOrElse { e ->
- Timber.e("Failed to load app currency: $e")
- AppCurrency.Default
- }
- }
- .distinctUntilChanged()
- }
-
- private fun getBalanceHidingSettingsFlow(): Flow {
- return getBalanceHidingSettingsUseCase()
- .map { it.isBalanceHidden }
- .distinctUntilChanged()
- }
-
private fun getWalletsWithTotalBalanceFlow(
ids: List,
): Flow