Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-22 16:17:51 +07:00
parent 0c5d018677
commit 35fd75485c
15 changed files with 413 additions and 30 deletions

View file

@ -12,6 +12,7 @@
<string name="access_code_create_description">ウォレットのロックを解除するには、 %s桁のアクセスコードを設定します。</string>
<string name="access_code_create_title">アクセスコードの作成</string>
<string name="access_code_navtitle">アクセスコード</string>
<string name="account_archived_accounts">アーカイブされたアカウント</string>
<string name="account_archived_recover">回復する</string>
<string name="account_archived_title">アーカイブ済み</string>
<string name="account_details_archive">アカウントをアーカイブする</string>
@ -26,6 +27,7 @@
<string name="account_form_placeholder_new_account">新しいアカウント</string>
<string name="account_form_title_create">アカウントを追加</string>
<string name="account_form_title_edit">アカウントを編集</string>
<string name="account_reorder_description">アカウントを長押しして並べ替える</string>
<string name="account_unsaved_dialog_action_first">編集を続ける</string>
<string name="account_unsaved_dialog_action_second">破棄</string>
<string name="account_unsaved_dialog_message_create">新しいアカウントを破棄してもよろしいですか?</string>
@ -116,6 +118,12 @@
<string name="biometric_lockout_warning_description">30秒後に再試行するか、カードまたはリングをスキャンしてください</string>
<string name="biometric_lockout_warning_title">試行回数が多すぎます</string>
<string name="biometric_unavailable_warning">お使いの携帯電話で生体認証が無効になっているため、アプリにウォレットを保存できません。ウォレットを保存するには、携帯電話の設定で生体認証機能を有効にしてください。</string>
<string name="bitcoin_promo_activation_error">プロモーションコードの処理中にエラーが発生しました。しばらくしてからもう一度お試しください。</string>
<string name="bitcoin_promo_activation_success">プロモーションコードが正常に有効化されました。14日以内に10 USDT相当のビットコインボーナスが付与されます。</string>
<string name="bitcoin_promo_activation_success_title">プロモーションコードが有効になりました</string>
<string name="bitcoin_promo_already_activated">このプロモーションコードは既に使用されているため、再度使うことはできません。</string>
<string name="bitcoin_promo_invalid_code">このプロモーションコードは無効であり、有効化できません。</string>
<string name="bitcoin_promo_no_address">ボーナスを受け取るにはビットコインアドレスが必要です。ウォレットにビットコインアドレスを追加し、再度アクティベーションをお試しください。</string>
<string name="button_start_backup_process">バックアップ処理を開始する</string>
<string name="buy_token_description">銀行カードまたはその他の支払い方法を使用する</string>
<plurals name="card_label_card_count">
@ -149,6 +157,7 @@
<string name="cardano_max_amount_has_token_title">ADAが不足しています。</string>
<string name="common_accept">受け入れる</string>
<string name="common_access_denied">アクセスが拒否されました</string>
<string name="common_accounts">アカウント</string>
<string name="common_add">追加</string>
<string name="common_add_to_portfolio">ポートフォリオに追加</string>
<string name="common_add_token">トークンを追加</string>

View file

@ -59,6 +59,16 @@
<string name="biometric_lockout_warning_description">Пожалуйста, попробуйте снова через 30 секунд или отсканируйте карту или кольцо</string>
<string name="biometric_lockout_warning_title">Слишком много попыток</string>
<string name="biometric_unavailable_warning">Вы отключили биометрическую аутентификацию на вашем телефоне и не сможете сохранять кошельки в приложении. Для сохранения кошельков, пожалуйста, включите функцию биометрической аутентификации в настройках телефона.</string>
<string name="bitcoin_promo_activation_error">При обработке промокода произошла ошибка. Пожалуйста, попробуйте позже.</string>
<string name="bitcoin_promo_activation_error_title">Ошибка активации</string>
<string name="bitcoin_promo_activation_success">Ваш промокод успешно активирован. Бонус 10 USDT в Bitcoin будет зачислен через 14 дней.</string>
<string name="bitcoin_promo_activation_success_title">Промокод активирован</string>
<string name="bitcoin_promo_already_activated">Этот промокод уже был использован и не может быть активирован повторно.</string>
<string name="bitcoin_promo_already_activated_title">Код недоступен</string>
<string name="bitcoin_promo_invalid_code">Этот промокод недействителен и не может быть активирован.</string>
<string name="bitcoin_promo_invalid_code_title">Неверный код</string>
<string name="bitcoin_promo_no_address">Для зачисления бонуса нужен Bitcoin-адрес. Добавьте его в портфель и повторите активацию.</string>
<string name="bitcoin_promo_no_address_title">Требуется Bitcoin-адрес</string>
<string name="button_start_backup_process">Начать резервное копирование</string>
<string name="buy_token_description">Используйте банковскую карту или другие методы оплаты</string>
<plurals name="card_label_card_count">

View file

@ -59,6 +59,16 @@
<string name="biometric_lockout_warning_description">Будь ласка, спробуйте знову через 30 секунд або відскануйте картку або кільце</string>
<string name="biometric_lockout_warning_title">Забагато спроб</string>
<string name="biometric_unavailable_warning">Ви вимкнули біометричну автентифікацію на своєму телефоні і не зможете зберігати гаманці в додатку. Щоб зберегти гаманці, будь ласка, увімкніть функцію біометричної автентифікації в налаштуваннях телефону.</string>
<string name="bitcoin_promo_activation_error">Під час обробки промокоду сталася помилка. Будь ласка, спробуйте пізніше.</string>
<string name="bitcoin_promo_activation_error_title">Помилка активації</string>
<string name="bitcoin_promo_activation_success">Ваш промокод успішно активовано. Бонус 10 USDT у Bitcoin буде зараховано через 14 днів.</string>
<string name="bitcoin_promo_activation_success_title">Промокод активовано</string>
<string name="bitcoin_promo_already_activated">Цей промокод уже був використаний і не може бути активований повторно.</string>
<string name="bitcoin_promo_already_activated_title">Код недоступний</string>
<string name="bitcoin_promo_invalid_code">Цей промокод недійсний і не може бути активований.</string>
<string name="bitcoin_promo_invalid_code_title">Невірний код</string>
<string name="bitcoin_promo_no_address">Для зарахування бонусу потрібна Bitcoin-адреса. Додайте її до портфеля та повторіть активацію.</string>
<string name="bitcoin_promo_no_address_title">Потрібна Bitcoin-адреса</string>
<string name="button_start_backup_process">Почніть процес резервного копіювання</string>
<string name="buy_token_description">Використовуйте банківську картку або інші способи оплати</string>
<plurals name="card_label_card_count">

View file

@ -12,7 +12,12 @@
<string name="access_code_create_description">Set a %s-digit Access Code to unlock your wallet.</string>
<string name="access_code_create_title">Create Access Code</string>
<string name="access_code_navtitle">Access code</string>
<string name="account_add_limit_dialog_description">You cannot create more than %1$s accounts. Archive one to add new.</string>
<string name="account_add_limit_dialog_title">Cant add new account</string>
<string name="account_archived_accounts">Archived accounts</string>
<string name="account_archived_recover">Recover</string>
<string name="account_archived_recover_dialog_description">Youre about to recover “%1$s”.</string>
<string name="account_archived_recover_dialog_title">Recover account</string>
<string name="account_archived_title">Archived</string>
<string name="account_details_archive">Archive account</string>
<string name="account_details_archive_action">Archive</string>
@ -26,6 +31,8 @@
<string name="account_form_placeholder_new_account">New account</string>
<string name="account_form_title_create">Add account</string>
<string name="account_form_title_edit">Edit account</string>
<string name="account_label_tokens_info">%1$s in %2$s</string>
<string name="account_reorder_description">Long tap on an account to reorder accounts</string>
<string name="account_unsaved_dialog_action_first">Keep Editing</string>
<string name="account_unsaved_dialog_action_second">Discard</string>
<string name="account_unsaved_dialog_message_create">Are you sure you want to discard new account?</string>
@ -117,6 +124,12 @@
<string name="biometric_lockout_warning_description">Please try again in 30 seconds or scan the card or ring</string>
<string name="biometric_lockout_warning_title">Too many attempts</string>
<string name="biometric_unavailable_warning">You have disabled biometric authentication on your phone and will not be able to save wallets in the app. To save wallets, please enable the biometric authentication function in your phone settings.</string>
<string name="bitcoin_promo_activation_error">An error occurred while processing your promo code. Please try again later.</string>
<string name="bitcoin_promo_activation_success">Your promo code has been successfully activated. A bonus of 10 USDT in Bitcoin will be credited in 14 days.</string>
<string name="bitcoin_promo_activation_success_title">Promo code activated</string>
<string name="bitcoin_promo_already_activated">This promo code has already been used and cannot be activated again.</string>
<string name="bitcoin_promo_invalid_code">This promo code is not valid and cannot be activated.</string>
<string name="bitcoin_promo_no_address">A Bitcoin address is required to receive the bonus. Please add one to your wallet and retry the activation.</string>
<string name="button_start_backup_process">Start backup process</string>
<string name="buy_token_description">Use a bank card or other payment methods</string>
<plurals name="card_label_card_count">
@ -152,6 +165,7 @@
<string name="cardano_max_amount_has_token_title">Not enough ADA</string>
<string name="common_accept">Accept</string>
<string name="common_access_denied">Access denied</string>
<string name="common_accounts">Accounts</string>
<string name="common_add">Add</string>
<string name="common_add_to_portfolio">Add to portfolio</string>
<string name="common_add_token">Add token</string>
@ -239,6 +253,10 @@
<string name="common_month">month</string>
<string name="common_network_fee_title">Network fee</string>
<string name="common_network_fee_warning_content">Amount sent will be reduced by %1$s (%2$s) to cover the selected fee level</string>
<plurals name="common_networks_count">
<item quantity="one">%d network</item>
<item quantity="other">%d networks</item>
</plurals>
<string name="common_next">Next</string>
<string name="common_nft">NFT</string>
<string name="common_no">No</string>

View file

@ -5,9 +5,8 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.res.R
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.domain.account.usecase.RecoverCryptoPortfolioUseCase
@ -48,8 +47,11 @@ internal class ArchivedAccountListModel @Inject constructor(
)
messageSender.send(
DialogMessage(
title = stringReference(account.accountName.value),
message = TextReference.EMPTY,
title = resourceReference(R.string.account_archived_recover_dialog_title),
message = resourceReference(
id = R.string.account_archived_recover_dialog_description,
formatArgs = wrappedList(account.accountName.value),
),
firstActionBuilder = { firstAction },
secondActionBuilder = { secondAction },
),

View file

@ -5,7 +5,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.account.CryptoPortfolioIcon
import kotlinx.collections.immutable.ImmutableList
data class AccountCreateEditUM(
internal data class AccountCreateEditUM(
val title: TextReference,
val account: Account,
val colorsState: Colors,

View file

@ -2,7 +2,7 @@ package com.tangem.features.account.details.entity
import com.tangem.common.ui.account.CryptoPortfolioIconUM
data class AccountDetailsUM(
internal data class AccountDetailsUM(
val accountName: String,
val accountIcon: CryptoPortfolioIconUM,
val onCloseClick: () -> Unit,

View file

@ -29,6 +29,7 @@ dependencies {
implementation(projects.core.analytics)
implementation(projects.core.analytics.models)
implementation(projects.common.routing)
implementation(projects.common.ui)
/* Project - Domain */
implementation(projects.domain.legacy)

View file

@ -1,6 +1,7 @@
package com.tangem.feature.walletsettings.component.impl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -13,6 +14,7 @@ import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableDialogComponent
import com.tangem.core.ui.utils.requestPermission
import com.tangem.feature.walletsettings.component.NetworksAvailableForNotificationsComponent
import com.tangem.feature.walletsettings.component.RenameWalletComponent
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
@ -20,6 +22,7 @@ import com.tangem.feature.walletsettings.entity.DialogConfig
import com.tangem.feature.walletsettings.entity.NetworksAvailableForNotificationBSConfig
import com.tangem.feature.walletsettings.model.WalletSettingsModel
import com.tangem.feature.walletsettings.ui.WalletSettingsScreen
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -61,6 +64,18 @@ internal class DefaultWalletSettingsComponent @AssistedInject constructor(
dialog = { dialog.child?.instance?.Dialog() },
)
val requestPushPermission = requestPermission(
onAllow = { state.onPushNotificationPermissionGranted(true) },
onDeny = { state.onPushNotificationPermissionGranted(false) },
permission = PUSH_PERMISSION,
)
if (state.requestPushNotificationsPermission) {
LaunchedEffect(Unit) {
requestPushPermission()
}
}
bottomSheet.child?.instance?.BottomSheet()
}

View file

@ -2,12 +2,19 @@ package com.tangem.feature.walletsettings.component.preview
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.common.ui.account.AccountIconPreviewData
import com.tangem.core.analytics.DummyAnalyticsEventHandler
import com.tangem.core.decompose.navigation.DummyRouter
import com.tangem.core.ui.components.block.model.BlockUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
import com.tangem.feature.walletsettings.entity.WalletSettingsAccountsUM
import com.tangem.feature.walletsettings.entity.WalletSettingsAccountsUM.Footer.AddAccountUM
import com.tangem.feature.walletsettings.entity.WalletSettingsUM
import com.tangem.feature.walletsettings.impl.R
import com.tangem.feature.walletsettings.ui.WalletSettingsScreen
import com.tangem.feature.walletsettings.utils.ItemsBuilder
import com.tangem.hot.sdk.model.HotWalletId
@ -48,11 +55,41 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent {
walletUpgradeDismissed = false,
onUpgradeWalletClick = {},
onDismissUpgradeWalletClick = {},
accountsUM = previewAccounts(),
),
requestPushNotificationsPermission = false,
onPushNotificationPermissionGranted = {},
)
private fun previewAccounts() = buildList {
WalletSettingsAccountsUM.Header(
id = "accounts_header",
text = resourceReference(R.string.common_accounts),
).let(::add)
WalletSettingsAccountsUM.Account(
id = "accountId",
accountName = stringReference("Main account"),
accountIconUM = AccountIconPreviewData.randomAccountIcon(),
tokensInfo = stringReference("10 tokens"),
networksInfo = stringReference("2 networks"),
onClick = {},
).let(::add)
WalletSettingsAccountsUM.Footer(
id = "accounts_footer",
addAccount = AddAccountUM(
title = resourceReference(R.string.account_form_title_create),
addAccountEnabled = true,
onAddAccountClick = {},
),
archivedAccounts = BlockUM(
text = resourceReference(R.string.account_archived_accounts),
iconRes = R.drawable.ic_archive_24,
onClick = {},
),
description = resourceReference(R.string.account_reorder_description),
).let(::add)
}
@Composable
override fun Content(modifier: Modifier) {
WalletSettingsScreen(

View file

@ -1,6 +1,7 @@
package com.tangem.feature.walletsettings.entity
import androidx.compose.runtime.Immutable
import com.tangem.common.ui.account.CryptoPortfolioIconUM
import com.tangem.core.ui.components.block.model.BlockUM
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.ImmutableList
@ -51,4 +52,36 @@ internal sealed class WalletSettingsItemUM {
val onClick: () -> Unit,
val onDismissClick: () -> Unit,
) : WalletSettingsItemUM()
}
@Immutable
internal sealed class WalletSettingsAccountsUM : WalletSettingsItemUM() {
data class Header(
override val id: String,
val text: TextReference,
) : WalletSettingsAccountsUM()
data class Account(
override val id: String,
val accountName: TextReference,
val accountIconUM: CryptoPortfolioIconUM,
val tokensInfo: TextReference,
val networksInfo: TextReference,
val onClick: () -> Unit,
) : WalletSettingsAccountsUM()
data class Footer(
override val id: String,
val addAccount: AddAccountUM,
val archivedAccounts: BlockUM,
val description: TextReference,
) : WalletSettingsAccountsUM() {
data class AddAccountUM(
val title: TextReference,
val addAccountEnabled: Boolean,
val onAddAccountClick: () -> Unit,
)
}
}

View file

@ -15,11 +15,7 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
import com.tangem.core.ui.components.bottomsheets.message.icon
import com.tangem.core.ui.components.bottomsheets.message.infoBlock
import com.tangem.core.ui.components.bottomsheets.message.onClick
import com.tangem.core.ui.components.bottomsheets.message.secondaryButton
import com.tangem.core.ui.components.bottomsheets.message.*
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
@ -29,6 +25,7 @@ import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.DisableWalletNFTUseCase
import com.tangem.domain.nft.EnableWalletNFTUseCase
import com.tangem.domain.nft.GetWalletNFTEnabledUseCase
@ -36,7 +33,6 @@ import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUse
import com.tangem.domain.notifications.repository.NotificationsRepository
import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles
import com.tangem.domain.settings.repositories.PermissionRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.usecase.*
import com.tangem.feature.walletsettings.analytics.Settings
import com.tangem.feature.walletsettings.analytics.WalletSettingsAnalyticEvents
@ -46,6 +42,7 @@ import com.tangem.feature.walletsettings.entity.NetworksAvailableForNotification
import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.entity.WalletSettingsUM
import com.tangem.feature.walletsettings.impl.R
import com.tangem.feature.walletsettings.utils.AccountItemsDelegate
import com.tangem.feature.walletsettings.utils.ItemsBuilder
import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -65,6 +62,7 @@ internal class WalletSettingsModel @Inject constructor(
private val messageSender: UiMessageSender,
private val deleteWalletUseCase: DeleteWalletUseCase,
private val itemsBuilder: ItemsBuilder,
private val accountItemsDelegate: AccountItemsDelegate,
override val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventHandler: AnalyticsEventHandler,
private val analyticsContextProxy: AnalyticsContextProxy,
@ -224,6 +222,7 @@ internal class WalletSettingsModel @Inject constructor(
walletUpgradeDismissed = isUpgradeNotificationEnabled,
onUpgradeWalletClick = ::onUpgradeWalletClick,
onDismissUpgradeWalletClick = ::onDismissUpgradeWalletClick,
accountsUM = with(accountItemsDelegate) { listOf() }, // todo account
)
}

View file

@ -2,20 +2,29 @@ package com.tangem.feature.walletsettings.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
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.testTag
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.account.AccountRow
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH8
import com.tangem.core.ui.components.TangemSwitch
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
@ -30,12 +39,11 @@ 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.WalletSettingsScreenTestTags
import com.tangem.core.ui.utils.requestPermission
import com.tangem.feature.walletsettings.component.preview.PreviewWalletSettingsComponent
import com.tangem.feature.walletsettings.entity.WalletSettingsAccountsUM
import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.entity.WalletSettingsUM
import com.tangem.feature.walletsettings.impl.R
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
@Composable
internal fun WalletSettingsScreen(
@ -71,7 +79,6 @@ internal fun WalletSettingsScreen(
private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) {
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
contentPadding = PaddingValues(
top = TangemTheme.dimens.spacing16,
bottom = TangemTheme.dimens.spacing16,
@ -89,8 +96,17 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) {
items = state.items,
key = WalletSettingsItemUM::id,
) { item ->
val itemModifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
val offsetModifier = when (item) {
is WalletSettingsAccountsUM.Account,
is WalletSettingsAccountsUM.Footer,
-> Modifier.padding(horizontal = TangemTheme.dimens.spacing16)
else -> Modifier.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing16,
)
}
val itemModifier = offsetModifier
.fillMaxWidth()
.testTag(WalletSettingsScreenTestTags.SCREEN_ITEM)
@ -121,21 +137,12 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) {
modifier = itemModifier,
model = item,
)
is WalletSettingsAccountsUM.Header -> AccountsHeader(item, itemModifier)
is WalletSettingsAccountsUM.Account -> AccountItem(item, itemModifier)
is WalletSettingsAccountsUM.Footer -> AccountsFooter(item, itemModifier)
}
}
}
val requestPushPermission = requestPermission(
onAllow = { state.onPushNotificationPermissionGranted(true) },
onDeny = { state.onPushNotificationPermissionGranted(false) },
permission = PUSH_PERMISSION,
)
if (state.requestPushNotificationsPermission) {
LaunchedEffect(Unit) {
requestPushPermission()
}
}
}
@Composable
@ -257,6 +264,134 @@ private fun NotificationAlertBlock(model: WalletSettingsItemUM.NotificationPermi
)
}
@Composable
private fun AccountsHeader(model: WalletSettingsAccountsUM.Header, modifier: Modifier = Modifier) {
Text(
modifier = modifier
.background(
shape = RoundedCornerShape(
topStart = TangemTheme.dimens.radius16,
topEnd = TangemTheme.dimens.radius16,
),
color = TangemTheme.colors.background.primary,
)
.padding(
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
top = TangemTheme.dimens.spacing8,
bottom = TangemTheme.dimens.spacing4,
),
text = model.text.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
@Composable
private fun AccountItem(model: WalletSettingsAccountsUM.Account, modifier: Modifier = Modifier) {
val subtitle = stringResourceSafe(
id = R.string.account_label_tokens_info,
formatArgs = arrayOf(
model.tokensInfo.resolveReference(),
model.networksInfo.resolveReference(),
),
)
AccountRow(
modifier = modifier
.background(color = TangemTheme.colors.background.primary)
.clickable(onClick = model.onClick)
.padding(12.dp),
title = model.accountName,
subtitle = stringReference(subtitle),
icon = model.accountIconUM,
)
}
@Composable
private fun AccountsFooter(model: WalletSettingsAccountsUM.Footer, modifier: Modifier = Modifier) {
Column(modifier) {
Column(
modifier = Modifier.background(
shape = RoundedCornerShape(
bottomStart = TangemTheme.dimens.radius16,
bottomEnd = TangemTheme.dimens.radius16,
),
color = TangemTheme.colors.background.primary,
),
) {
AddAccountRow(model.addAccount)
SpacerH(
height = TangemTheme.dimens.size0_5,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing12)
.background(TangemTheme.colors.stroke.primary),
)
BlockItem(
modifier = Modifier.fillMaxWidth(),
model = model.archivedAccounts,
)
}
SpacerH8()
Text(
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12),
text = model.description.resolveReference(),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.caption2,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
@Composable
private fun AddAccountRow(model: WalletSettingsAccountsUM.Footer.AddAccountUM, modifier: Modifier = Modifier) {
val iconTint: Color
val backgroundColor: Color
val textColor: Color
if (model.addAccountEnabled) {
iconTint = TangemTheme.colors.icon.accent
backgroundColor = TangemTheme.colors.icon.accent.copy(alpha = 0.1f)
textColor = TangemTheme.colors.text.accent
} else {
iconTint = TangemTheme.colors.icon.inactive
backgroundColor = TangemTheme.colors.field.primary
textColor = TangemTheme.colors.text.disabled
}
Row(
modifier = modifier
.clickable(onClick = model.onAddAccountClick)
.fillMaxWidth()
.padding(12.dp),
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(36.dp)
.clip(RoundedCornerShape(10.dp))
.background(backgroundColor)
.clickable(onClick = { model.onAddAccountClick() }),
) {
Icon(
modifier = Modifier.size(18.dp),
tint = iconTint,
imageVector = ImageVector.vectorResource(id = R.drawable.ic_plus_24),
contentDescription = null,
)
}
Text(
text = model.title.resolveReference(),
color = textColor,
style = TangemTheme.typography.subtitle1,
)
}
}
@Composable
private fun DescriptionWithMoreBlock(
model: WalletSettingsItemUM.DescriptionWithMore,

View file

@ -0,0 +1,111 @@
package com.tangem.feature.walletsettings.utils
import com.tangem.common.routing.AppRoute
import com.tangem.common.ui.account.toUM
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.components.block.model.BlockUM
import com.tangem.core.ui.extensions.pluralReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.walletsettings.entity.WalletSettingsAccountsUM
import com.tangem.feature.walletsettings.entity.WalletSettingsAccountsUM.Footer.AddAccountUM
import com.tangem.feature.walletsettings.impl.R
import javax.inject.Inject
@ModelScoped
internal class AccountItemsDelegate @Inject constructor(
private val router: Router,
private val messageSender: UiMessageSender,
) {
fun buildUiList(userWalletId: UserWalletId, accounts: List<Account>): List<WalletSettingsAccountsUM> = buildList {
WalletSettingsAccountsUM.Header(
id = "accounts_header",
text = resourceReference(R.string.common_accounts),
).let(::add)
addAll(accounts.map(::mapAccount))
val addAccountEnabled = true // todo account
WalletSettingsAccountsUM.Footer(
id = "accounts_footer",
addAccount = AddAccountUM(
title = resourceReference(R.string.account_form_title_create),
addAccountEnabled = addAccountEnabled,
onAddAccountClick = {
if (addAccountEnabled) openAddAccount(userWalletId) else canNotAddAccountDialog()
},
),
archivedAccounts = BlockUM(
text = resourceReference(R.string.account_archived_accounts),
iconRes = R.drawable.ic_archive_24,
onClick = { openArchivedAccounts(userWalletId) },
),
description = resourceReference(R.string.account_reorder_description),
).let(::add)
}
private fun mapAccount(account: Account): WalletSettingsAccountsUM = when (account) {
is Account.CryptoPortfolio -> account.mapCryptoPortfolio()
}
private fun Account.CryptoPortfolio.mapCryptoPortfolio(): WalletSettingsAccountsUM {
return WalletSettingsAccountsUM.Account(
id = accountId.value,
accountName = stringReference(accountName.value),
accountIconUM = icon.toUM(),
tokensInfo = pluralReference(
R.plurals.common_tokens_count,
count = tokensCount,
formatArgs = wrappedList(tokensCount),
),
networksInfo = pluralReference(
R.plurals.common_networks_count,
count = networksCount,
formatArgs = wrappedList(networksCount),
),
onClick = { openAccountDetails(this) },
)
}
private fun openAccountDetails(account: Account) {
router.push(AppRoute.AccountDetails(account))
}
private fun openArchivedAccounts(userWalletId: UserWalletId) {
router.push(AppRoute.ArchivedAccountList(userWalletId))
}
private fun openAddAccount(userWalletId: UserWalletId) {
router.push(AppRoute.CreateAccount(userWalletId))
}
private fun canNotAddAccountDialog() {
val firstAction = EventMessageAction(
title = resourceReference(R.string.common_got_it),
onClick = { },
)
messageSender.send(
DialogMessage(
title = resourceReference(R.string.account_add_limit_dialog_title),
message = resourceReference(
id = R.string.account_add_limit_dialog_description,
formatArgs = wrappedList(MAX_ACCOUNT_COUNT.toString()),
),
firstActionBuilder = { firstAction },
),
)
}
companion object {
// todo account use domain const?
private const val MAX_ACCOUNT_COUNT = 20
}
}

View file

@ -12,6 +12,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.walletsettings.analytics.Settings
import com.tangem.feature.walletsettings.entity.WalletSettingsAccountsUM
import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.impl.R
import com.tangem.hot.sdk.model.HotWalletId
@ -30,6 +31,7 @@ internal class ItemsBuilder @Inject constructor(
fun buildItems(
userWallet: UserWallet,
userWalletName: String,
accountsUM: List<WalletSettingsAccountsUM>,
isLinkMoreCardsAvailable: Boolean,
isReferralAvailable: Boolean,
isManageTokensAvailable: Boolean,
@ -60,6 +62,7 @@ internal class ItemsBuilder @Inject constructor(
onDismissUpgradeWalletClick = onDismissUpgradeWalletClick,
),
)
.addAll(accountsUM)
.addAll(buildAccessCodeItem(userWallet, onAccessCodeClick))
.add(
buildCardItem(