Updated on 2026-08-14
This commit is contained in:
commit
d61801a6d4
18 changed files with 414 additions and 383 deletions
|
|
@ -0,0 +1,340 @@
|
|||
package com.tangem.common.ui.bottomsheets
|
||||
|
||||
import android.content.res.Configuration
|
||||
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.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
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.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.window.PopupProperties
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.bottomsheets.state.*
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithAdditionalButtons
|
||||
import com.tangem.core.ui.components.appbar.models.AdditionalButton
|
||||
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun GiveTxPermissionBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) { content: GiveTxPermissionBottomSheetConfig ->
|
||||
GiveTxPermissionBottomSheetContent(content = content)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun GiveTxPermissionBottomSheetContent(content: GiveTxPermissionBottomSheetConfig) {
|
||||
var isPermissionAlertShow by remember { mutableStateOf(false) }
|
||||
val data = content.data
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(color = TangemTheme.colors.background.secondary)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AppBarWithAdditionalButtons(
|
||||
text = resourceReference(id = R.string.give_permission_title),
|
||||
iconColor = TangemTheme.colors.text.tertiary,
|
||||
endButton = AdditionalButton(
|
||||
iconRes = R.drawable.ic_information_24,
|
||||
onIconClicked = { isPermissionAlertShow = true },
|
||||
),
|
||||
)
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.give_permission_subtitle,
|
||||
data.currency,
|
||||
),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body2,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing24),
|
||||
)
|
||||
|
||||
SpacerH16()
|
||||
|
||||
ApprovalBottomSheetInfo(data)
|
||||
|
||||
SpacerH(height = TangemTheme.dimens.spacing20)
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResource(id = R.string.common_approve),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
onClick = data.approveButton.onClick,
|
||||
)
|
||||
|
||||
SpacerH12()
|
||||
|
||||
SecondaryButton(
|
||||
text = stringResource(id = R.string.common_cancel),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
onClick = content.onCancel,
|
||||
)
|
||||
|
||||
SpacerH16()
|
||||
|
||||
// region dialog
|
||||
if (isPermissionAlertShow) {
|
||||
BasicDialog(
|
||||
message = stringResource(id = R.string.swapping_approve_information_text),
|
||||
title = stringResource(id = R.string.swapping_approve_information_title),
|
||||
confirmButton = DialogButton { isPermissionAlertShow = false },
|
||||
onDismissDialog = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ApprovalBottomSheetInfo(data: GiveTxPermissionState.ReadyForRequest) {
|
||||
FooterContainer(
|
||||
footer = stringResource(id = R.string.give_permission_policy_type_footer),
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
AmountItem(
|
||||
currency = data.currency,
|
||||
approveType = data.approveType,
|
||||
onChangeApproveType = data.onChangeApproveType,
|
||||
approveItems = data.approveItems,
|
||||
)
|
||||
}
|
||||
SpacerH16()
|
||||
FooterContainer(
|
||||
footer = stringResource(id = R.string.give_permission_fee_footer),
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
FeeItem(fee = data.fee)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeeItem(fee: TextReference) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.common_network_fee_title),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
maxLines = 1,
|
||||
)
|
||||
EllipsisText(
|
||||
text = fee.resolveReference(),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.body1,
|
||||
modifier = Modifier.padding(start = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AmountItem(
|
||||
currency: String,
|
||||
approveType: ApproveType,
|
||||
approveItems: ImmutableList<ApproveType>,
|
||||
onChangeApproveType: (ApproveType) -> Unit,
|
||||
) {
|
||||
var isExpandSelector by remember { mutableStateOf(false) }
|
||||
var amountSize by remember { mutableStateOf(IntSize.Zero) }
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(),
|
||||
onClick = { isExpandSelector = true },
|
||||
),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.onSizeChanged { amountSize = it }
|
||||
.padding(
|
||||
top = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.give_permission_rows_amount, currency),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
maxLines = 1,
|
||||
)
|
||||
when (approveType) {
|
||||
ApproveType.LIMITED -> {
|
||||
Text(
|
||||
text = stringResource(id = R.string.give_permission_current_transaction),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.body1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
ApproveType.UNLIMITED -> {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
image = ImageVector.vectorResource(id = R.drawable.ic_infinity_24),
|
||||
),
|
||||
tint = TangemTheme.colors.text.tertiary,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DropdownSelector(
|
||||
isExpanded = isExpandSelector,
|
||||
onDismiss = { isExpandSelector = false },
|
||||
onItemClick = { approveType ->
|
||||
isExpandSelector = false
|
||||
onChangeApproveType.invoke(approveType)
|
||||
},
|
||||
items = approveItems,
|
||||
selectedType = approveType,
|
||||
amountSize = amountSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun DropdownSelector(
|
||||
isExpanded: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onItemClick: (ApproveType) -> Unit,
|
||||
items: ImmutableList<ApproveType>,
|
||||
selectedType: ApproveType,
|
||||
amountSize: IntSize,
|
||||
) {
|
||||
var dropDownWidth by remember { mutableStateOf(IntSize.Zero) }
|
||||
val offsetY = amountSize.height.times(-1)
|
||||
val offsetX = amountSize.width - dropDownWidth.width
|
||||
|
||||
// Workaround to set color and shape of dropdown menu
|
||||
MaterialTheme(
|
||||
colorScheme = MaterialTheme.colorScheme.copy(surface = TangemTheme.colors.background.action),
|
||||
shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(TangemTheme.dimens.radius16)),
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = isExpanded,
|
||||
onDismissRequest = onDismiss,
|
||||
properties = PopupProperties(clippingEnabled = false),
|
||||
offset = with(LocalDensity.current) {
|
||||
DpOffset(x = offsetX.toDp(), y = offsetY.toDp())
|
||||
},
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.onSizeChanged { dropDownWidth = it },
|
||||
) {
|
||||
items.forEach { item ->
|
||||
val color = if (item == selectedType) TangemTheme.colors.icon.accent else Color.Transparent
|
||||
|
||||
DropdownMenuItem(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = {
|
||||
Row {
|
||||
Text(
|
||||
text = when (item) {
|
||||
ApproveType.LIMITED -> stringResource(
|
||||
id = R.string.give_permission_current_transaction,
|
||||
)
|
||||
ApproveType.UNLIMITED -> stringResource(id = R.string.give_permission_unlimited)
|
||||
},
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.body1,
|
||||
maxLines = 1,
|
||||
)
|
||||
SpacerWMax()
|
||||
Icon(
|
||||
painter = rememberVectorPainter(
|
||||
image = ImageVector.vectorResource(id = R.drawable.ic_check_24),
|
||||
),
|
||||
tint = color,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(start = TangemTheme.dimens.size20),
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
onItemClick.invoke(item)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_AgreementBottomSheet() {
|
||||
TangemThemePreview {
|
||||
GiveTxPermissionBottomSheetContent(content = previewData)
|
||||
}
|
||||
}
|
||||
|
||||
private val previewData = GiveTxPermissionBottomSheetConfig(
|
||||
data = GiveTxPermissionState.ReadyForRequest(
|
||||
currency = "DAI",
|
||||
amount = "1",
|
||||
walletAddress = "",
|
||||
spenderAddress = "",
|
||||
fee = TextReference.Str("2,14$"),
|
||||
approveType = ApproveType.UNLIMITED,
|
||||
approveButton = ApprovePermissionButton(true) {},
|
||||
cancelButton = CancelPermissionButton(true),
|
||||
onChangeApproveType = { ApproveType.UNLIMITED },
|
||||
),
|
||||
onCancel = {},
|
||||
)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.common.ui.bottomsheets.state
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
|
||||
data class GiveTxPermissionBottomSheetConfig(
|
||||
val data: GiveTxPermissionState.ReadyForRequest,
|
||||
val onCancel: () -> Unit,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
package com.tangem.feature.swap.models
|
||||
package com.tangem.common.ui.bottomsheets.state
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapApproveType
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
sealed class SwapPermissionState {
|
||||
sealed class GiveTxPermissionState {
|
||||
|
||||
object InProgress : SwapPermissionState()
|
||||
data object InProgress : GiveTxPermissionState()
|
||||
|
||||
object Empty : SwapPermissionState()
|
||||
data object Empty : GiveTxPermissionState()
|
||||
|
||||
data class ReadyForRequest(
|
||||
val currency: String,
|
||||
|
|
@ -18,24 +17,17 @@ sealed class SwapPermissionState {
|
|||
val spenderAddress: String,
|
||||
val fee: TextReference,
|
||||
val approveType: ApproveType,
|
||||
val approveItems: ImmutableList<ApproveType> = ApproveType.values().toList().toImmutableList(),
|
||||
val approveItems: ImmutableList<ApproveType> = ApproveType.entries.toImmutableList(),
|
||||
val approveButton: ApprovePermissionButton,
|
||||
val cancelButton: CancelPermissionButton,
|
||||
val onChangeApproveType: (ApproveType) -> Unit,
|
||||
) : SwapPermissionState()
|
||||
) : GiveTxPermissionState()
|
||||
}
|
||||
|
||||
enum class ApproveType {
|
||||
LIMITED, UNLIMITED
|
||||
}
|
||||
|
||||
fun ApproveType.toDomainApproveType(): SwapApproveType {
|
||||
return when (this) {
|
||||
ApproveType.LIMITED -> SwapApproveType.LIMITED
|
||||
ApproveType.UNLIMITED -> SwapApproveType.UNLIMITED
|
||||
}
|
||||
}
|
||||
|
||||
data class ApprovePermissionButton(
|
||||
val enabled: Boolean,
|
||||
val loading: Boolean = false,
|
||||
|
|
@ -70,6 +70,7 @@
|
|||
<string name="common_access_denied">Доступ запрещен</string>
|
||||
<string name="common_apply">Применить</string>
|
||||
<string name="common_approval">Одобрение</string>
|
||||
<string name="common_approve">Подтвердить</string>
|
||||
<string name="common_attention">Внимание</string>
|
||||
<string name="common_balance">Баланс: %s</string>
|
||||
<string name="common_balance_title">Баланс</string>
|
||||
|
|
@ -261,6 +262,13 @@
|
|||
<string name="feedback_subject_support">Обращение в поддержку</string>
|
||||
<string name="feedback_subject_support_tangem">Обращение в поддержку Tangem</string>
|
||||
<string name="feedback_subject_tx_failed">Не могу отправить транзакцию</string>
|
||||
<string name="give_permission_current_transaction">Текущая транзакция</string>
|
||||
<string name="give_permission_fee_footer">Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена.</string>
|
||||
<string name="give_permission_policy_type_footer">Укажите лимит доступа к выбранному токену</string>
|
||||
<string name="give_permission_rows_amount">Количество %s</string>
|
||||
<string name="give_permission_subtitle">Чтобы продолжить, вам нужно разрешить смарт-контракту 1inch использовать ваш %s</string>
|
||||
<string name="give_permission_title">Дать разрешение</string>
|
||||
<string name="give_permission_unlimited">Безлимитно</string>
|
||||
<string name="home_button_order">Купить</string>
|
||||
<string name="home_button_scan">Сканировать</string>
|
||||
<string name="initial_message_change_access_code_body">Чтобы изменить код доступа, приложите карту как показано выше и не убирайте до окончания операции</string>
|
||||
|
|
@ -388,6 +396,7 @@
|
|||
<string name="onboarding_title">Активация карты</string>
|
||||
<string name="onboarding_title_backup_card_format">Резервная карта #%d</string>
|
||||
<string name="onboarding_title_no_backup_cards">Нет резервных карт</string>
|
||||
<string name="onboarding_title_notifications">Уведомления</string>
|
||||
<string name="onboarding_title_one_backup_card">Добавлена одна резервная карта</string>
|
||||
<string name="onboarding_title_scan_origin_card">Подготовьте свою карту</string>
|
||||
<string name="onboarding_title_two_backup_cards">Добавлены две резервные карты</string>
|
||||
|
|
@ -581,17 +590,9 @@
|
|||
<string name="swapping_approve_information_text">Подтверждения считаются отраслевым стандартом для всех децентрализованных бирж и защищают ваш кошелек от доступа со стороны смарт-контракта без вашего разрешения. По замыслу смарт-контракты не могут получить доступ к вашим токенам, если вы не одобрите доступ со своей стороны. «Разблокируя» свои токены, вы даете смарт-контракту 1inch разрешение тратить ваши активы. Майнеры сети получают компенсацию за газ (оплачиваемый вами) за запись этого действия в блокчейне. Как только разрешение будет предоставлено, вы сможете обменять свой токен.</string>
|
||||
<string name="swapping_approve_information_title">Подтвердить</string>
|
||||
<string name="swapping_from_title">Вы отправляете</string>
|
||||
<string name="swapping_give_permission">Дать разрешение</string>
|
||||
<string name="swapping_high_price_impact_description">Обмен этой суммы выбранных токенов может вызвать значительные колебания цены и уменьшить получаемую сумму.</string>
|
||||
<string name="swapping_insufficient_funds">Недостаточно средств</string>
|
||||
<string name="swapping_permission_buttons_approve">Подтвердить</string>
|
||||
<string name="swapping_permission_current_transaction">Текущая транзакция</string>
|
||||
<string name="swapping_permission_fee_footer">Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена.</string>
|
||||
<string name="swapping_permission_header">Дать разрешение</string>
|
||||
<string name="swapping_permission_policy_type_footer">Укажите лимит доступа к выбранному токену</string>
|
||||
<string name="swapping_permission_rows_amount">Количество %s</string>
|
||||
<string name="swapping_permission_subheader">Чтобы продолжить, вам нужно разрешить смарт-контракту 1inch использовать ваш %s</string>
|
||||
<string name="swapping_permission_unlimited">Безлимитно</string>
|
||||
<string name="swapping_success_view_title">В процессе</string>
|
||||
<string name="swapping_swap_action">Обменять</string>
|
||||
<string name="swapping_to_title">Вы получите</string>
|
||||
|
|
|
|||
|
|
@ -277,13 +277,9 @@
|
|||
<string name="story_web3_title">兼容Web3.0</string>
|
||||
<string name="swapping_approve_information_text">批准被視為所有去中心化交易所的行業標準,並保護您的錢包在未經您許可的情況下不被智能合約訪問。按照設計,智能合約無法訪問您的代幣,除非您從您的終端批准訪問。通過“解鎖”您的代幣,您將獲得 1inch 智能合約使用您的資產的權限。網絡的礦工將獲得Gas Fee(由您支付)作為補償,以在區塊鏈上記錄此操作。一旦獲得許可,您就可以交易您的代幣。</string>
|
||||
<string name="swapping_approve_information_title">批准</string>
|
||||
<string name="swapping_give_permission">賦予權限</string>
|
||||
<string name="swapping_high_price_impact_description">在此代幣交換的數量將對價格產生重大影響,並降低您收到的數量</string>
|
||||
<string name="swapping_insufficient_funds">餘額不足</string>
|
||||
<string name="swapping_permission_buttons_approve">允許</string>
|
||||
<string name="swapping_permission_header">賦予權限</string>
|
||||
<string name="swapping_permission_rows_amount">數量 %s</string>
|
||||
<string name="swapping_permission_subheader">要繼續,您需要允許 1inch 智能合約使用您的 %s</string>
|
||||
<string name="swapping_success_view_title">進行中</string>
|
||||
<string name="swapping_swap_action">交易</string>
|
||||
<string name="swapping_token_list_title">選擇代幣</string>
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
<string name="common_allow">Allow</string>
|
||||
<string name="common_apply">Apply</string>
|
||||
<string name="common_approval">Approval</string>
|
||||
<string name="common_approve">Approve</string>
|
||||
<string name="common_attention">Attention</string>
|
||||
<string name="common_balance">Balance: %s</string>
|
||||
<string name="common_balance_title">Balance</string>
|
||||
|
|
@ -264,6 +265,13 @@
|
|||
<string name="feedback_subject_support">Feedback</string>
|
||||
<string name="feedback_subject_support_tangem">Tangem feedback</string>
|
||||
<string name="feedback_subject_tx_failed">Can\'t send a transaction</string>
|
||||
<string name="give_permission_current_transaction">Current transaction</string>
|
||||
<string name="give_permission_fee_footer">The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap.</string>
|
||||
<string name="give_permission_policy_type_footer">Specify the approve limit for the selected token</string>
|
||||
<string name="give_permission_rows_amount">Amount %s</string>
|
||||
<string name="give_permission_subtitle">To continue, grant 1inch smart contracts permission to use your %s</string>
|
||||
<string name="give_permission_title">Give Permission</string>
|
||||
<string name="give_permission_unlimited">Unlimited</string>
|
||||
<string name="home_button_order">Order card</string>
|
||||
<string name="home_button_scan">Scan card</string>
|
||||
<string name="initial_message_change_access_code_body">To change the access code tap the card as shown above and do not remove until the end of the operation</string>
|
||||
|
|
@ -397,6 +405,7 @@
|
|||
<string name="onboarding_title">Activating card</string>
|
||||
<string name="onboarding_title_backup_card_format">Backup card #%d</string>
|
||||
<string name="onboarding_title_no_backup_cards">No backup cards</string>
|
||||
<string name="onboarding_title_notifications">Notifications</string>
|
||||
<string name="onboarding_title_one_backup_card">One backup card added</string>
|
||||
<string name="onboarding_title_scan_origin_card">Prepare your card</string>
|
||||
<string name="onboarding_title_two_backup_cards">Two backup cards added</string>
|
||||
|
|
@ -607,17 +616,9 @@
|
|||
<string name="swapping_approve_information_text">All decentralized exchanges require approvals to prevent smart contracts from accessing your wallet without your permission. By design, smart contracts can\'t access your tokens unless you approve. By \"unlocking\" your tokens, you authorize the 1-inch smart contract to spend them. The network\'s miners receive a gas fee (paid by you) to record this action on the blockchain. You can swap your token after giving approval.</string>
|
||||
<string name="swapping_approve_information_title">Approve</string>
|
||||
<string name="swapping_from_title">You swap</string>
|
||||
<string name="swapping_give_permission">Give Permission</string>
|
||||
<string name="swapping_high_price_impact_description">Swapping this amount of selected tokens will cause a significant price impact and reduce your outcome.</string>
|
||||
<string name="swapping_insufficient_funds">Insufficient funds</string>
|
||||
<string name="swapping_permission_buttons_approve">Approve</string>
|
||||
<string name="swapping_permission_current_transaction">Current transaction</string>
|
||||
<string name="swapping_permission_fee_footer">The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap.</string>
|
||||
<string name="swapping_permission_header">Give Permission</string>
|
||||
<string name="swapping_permission_policy_type_footer">Specify the approve limit for the selected token</string>
|
||||
<string name="swapping_permission_rows_amount">Amount %s</string>
|
||||
<string name="swapping_permission_subheader">To continue, grant 1inch smart contracts permission to use your %s</string>
|
||||
<string name="swapping_permission_unlimited">Unlimited</string>
|
||||
<string name="swapping_success_view_title">In progress</string>
|
||||
<string name="swapping_swap_action">Swap</string>
|
||||
<string name="swapping_to_title">You receive</string>
|
||||
|
|
@ -671,7 +672,7 @@
|
|||
<string name="unlock_wallet_description_full">Use %s or scan a card to have an access to your wallet</string>
|
||||
<string name="user_push_notification_agreement_argument_one">Stay up to date with the latest features and news</string>
|
||||
<string name="user_push_notification_agreement_argument_two">Be able to get important market notifications</string>
|
||||
<string name="user_push_notification_agreement_header">Would you like to use
Push-notifications?</string>
|
||||
<string name="user_push_notification_agreement_header">Would you like to use\nPush-notifications?</string>
|
||||
<string name="user_wallet_list_add_button">Add new wallet</string>
|
||||
<string name="user_wallet_list_delete_prompt">Are you sure you want to delete this wallet?</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">An error has occurred, please scan your card to log in</string>
|
||||
|
|
|
|||
5
core/ui/src/main/res/drawable/ic_infinity_24.xml
Normal file
5
core/ui/src/main/res/drawable/ic_infinity_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="#1E1E1E" android:pathData="M5.5,17.5C3.967,17.5 2.667,16.967 1.6,15.9C0.533,14.833 0,13.533 0,12C0,10.467 0.533,9.167 1.6,8.1C2.667,7.033 3.967,6.5 5.5,6.5C6.117,6.5 6.708,6.608 7.275,6.825C7.842,7.042 8.35,7.35 8.8,7.75L10.5,9.3L9,10.65L7.45,9.25C7.183,9.017 6.883,8.833 6.55,8.7C6.217,8.567 5.867,8.5 5.5,8.5C4.533,8.5 3.708,8.842 3.025,9.525C2.342,10.208 2,11.033 2,12C2,12.967 2.342,13.792 3.025,14.475C3.708,15.158 4.533,15.5 5.5,15.5C5.867,15.5 6.217,15.433 6.55,15.3C6.883,15.167 7.183,14.983 7.45,14.75L15.2,7.75C15.65,7.35 16.158,7.042 16.725,6.825C17.292,6.608 17.883,6.5 18.5,6.5C20.033,6.5 21.333,7.033 22.4,8.1C23.467,9.167 24,10.467 24,12C24,13.533 23.467,14.833 22.4,15.9C21.333,16.967 20.033,17.5 18.5,17.5C17.883,17.5 17.292,17.392 16.725,17.175C16.158,16.958 15.65,16.65 15.2,16.25L13.5,14.7L15,13.35L16.55,14.75C16.817,14.983 17.117,15.167 17.45,15.3C17.783,15.433 18.133,15.5 18.5,15.5C19.467,15.5 20.292,15.158 20.975,14.475C21.658,13.792 22,12.967 22,12C22,11.033 21.658,10.208 20.975,9.525C20.292,8.842 19.467,8.5 18.5,8.5C18.133,8.5 17.783,8.567 17.45,8.7C17.117,8.833 16.817,9.017 16.55,9.25L8.8,16.25C8.35,16.65 7.842,16.958 7.275,17.175C6.708,17.392 6.117,17.5 5.5,17.5Z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -20,6 +20,7 @@ dependencies {
|
|||
implementation(projects.core.utils)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.common.routing)
|
||||
implementation(projects.common.ui)
|
||||
|
||||
/** Domain modules **/
|
||||
implementation(projects.domain.appCurrency)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.feature.swap.analytics
|
||||
|
||||
import com.tangem.common.ui.bottomsheets.state.ApproveType
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapProvider
|
||||
import com.tangem.feature.swap.domain.models.ui.FeeType
|
||||
import com.tangem.feature.swap.models.ApproveType
|
||||
|
||||
private const val SWAP_CATEGORY = "Swap"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.swap.models
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.common.ui.bottomsheets.state.GiveTxPermissionState
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
|
|
@ -22,7 +23,7 @@ data class SwapStateHolder(
|
|||
val providerState: ProviderState,
|
||||
|
||||
val fee: FeeItemState = FeeItemState.Empty,
|
||||
val permissionState: SwapPermissionState = SwapPermissionState.Empty,
|
||||
val permissionState: GiveTxPermissionState = GiveTxPermissionState.Empty,
|
||||
val priceImpact: PriceImpact,
|
||||
|
||||
val successState: SwapSuccessStateHolder? = null,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.swap.models
|
||||
|
||||
import com.tangem.common.ui.bottomsheets.state.ApproveType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import com.tangem.feature.swap.domain.models.ui.TxFee
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.feature.swap.models.states
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.feature.swap.models.SwapPermissionState
|
||||
|
||||
data class GivePermissionBottomSheetConfig(
|
||||
val data: SwapPermissionState.ReadyForRequest,
|
||||
val onCancel: () -> Unit,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.swap.ui
|
|||
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.common.ui.bottomsheets.state.*
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
|
|
@ -649,7 +650,7 @@ internal class StateBuilder(
|
|||
),
|
||||
receiveCardData = receiveCardData,
|
||||
warnings = warnings,
|
||||
permissionState = SwapPermissionState.Empty,
|
||||
permissionState = GiveTxPermissionState.Empty,
|
||||
fee = FeeItemState.Empty,
|
||||
swapButton = SwapButton(
|
||||
enabled = false,
|
||||
|
|
@ -906,7 +907,7 @@ internal class StateBuilder(
|
|||
}
|
||||
|
||||
fun updateApproveType(uiState: SwapStateHolder, approveType: ApproveType): SwapStateHolder {
|
||||
val config = uiState.bottomSheetConfig?.content as? GivePermissionBottomSheetConfig
|
||||
val config = uiState.bottomSheetConfig?.content as? GiveTxPermissionBottomSheetConfig
|
||||
return if (config != null) {
|
||||
uiState.copy(
|
||||
bottomSheetConfig = uiState.bottomSheetConfig.copy(
|
||||
|
|
@ -980,7 +981,7 @@ internal class StateBuilder(
|
|||
),
|
||||
)
|
||||
return uiState.copy(
|
||||
permissionState = SwapPermissionState.InProgress,
|
||||
permissionState = GiveTxPermissionState.InProgress,
|
||||
warnings = warnings,
|
||||
)
|
||||
}
|
||||
|
|
@ -1140,27 +1141,27 @@ internal class StateBuilder(
|
|||
}
|
||||
|
||||
private fun convertPermissionState(
|
||||
lastPermissionState: SwapPermissionState,
|
||||
lastPermissionState: GiveTxPermissionState,
|
||||
permissionDataState: PermissionDataState,
|
||||
onGivePermissionClick: () -> Unit,
|
||||
onChangeApproveType: (ApproveType) -> Unit,
|
||||
): SwapPermissionState {
|
||||
val approveType = if (lastPermissionState is SwapPermissionState.ReadyForRequest) {
|
||||
): GiveTxPermissionState {
|
||||
val approveType = if (lastPermissionState is GiveTxPermissionState.ReadyForRequest) {
|
||||
lastPermissionState.approveType
|
||||
} else {
|
||||
ApproveType.UNLIMITED
|
||||
}
|
||||
return when (permissionDataState) {
|
||||
PermissionDataState.Empty -> SwapPermissionState.Empty
|
||||
PermissionDataState.PermissionFailed -> SwapPermissionState.Empty
|
||||
PermissionDataState.PermissionLoading -> SwapPermissionState.InProgress
|
||||
PermissionDataState.Empty -> GiveTxPermissionState.Empty
|
||||
PermissionDataState.PermissionFailed -> GiveTxPermissionState.Empty
|
||||
PermissionDataState.PermissionLoading -> GiveTxPermissionState.InProgress
|
||||
is PermissionDataState.PermissionReadyForRequest -> {
|
||||
val permissionFee = when (val fee = permissionDataState.requestApproveData.fee) {
|
||||
TxFeeState.Empty -> error("Fee shouldn't be empty")
|
||||
is TxFeeState.MultipleFeeState -> fee.priorityFee
|
||||
is TxFeeState.SingleFeeState -> fee.fee
|
||||
}
|
||||
SwapPermissionState.ReadyForRequest(
|
||||
GiveTxPermissionState.ReadyForRequest(
|
||||
currency = permissionDataState.currency,
|
||||
amount = permissionDataState.amount,
|
||||
approveType = approveType,
|
||||
|
|
@ -1193,8 +1194,8 @@ internal class StateBuilder(
|
|||
|
||||
fun showPermissionBottomSheet(uiState: SwapStateHolder, onDismiss: () -> Unit): SwapStateHolder {
|
||||
val permissionState = uiState.permissionState
|
||||
if (permissionState is SwapPermissionState.ReadyForRequest) {
|
||||
val config = GivePermissionBottomSheetConfig(
|
||||
if (permissionState is GiveTxPermissionState.ReadyForRequest) {
|
||||
val config = GiveTxPermissionBottomSheetConfig(
|
||||
data = permissionState,
|
||||
onCancel = onDismiss,
|
||||
)
|
||||
|
|
@ -1402,7 +1403,7 @@ internal class StateBuilder(
|
|||
return NotificationConfig(
|
||||
title = resourceReference(R.string.express_provider_permission_needed),
|
||||
subtitle = resourceReference(
|
||||
id = R.string.swapping_permission_subheader,
|
||||
id = R.string.give_permission_subtitle,
|
||||
formatArgs = wrappedList(fromTokenSymbol),
|
||||
),
|
||||
iconResId = R.drawable.ic_locked_24,
|
||||
|
|
|
|||
|
|
@ -1,317 +0,0 @@
|
|||
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.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.swap.models.ApprovePermissionButton
|
||||
import com.tangem.feature.swap.models.ApproveType
|
||||
import com.tangem.feature.swap.models.CancelPermissionButton
|
||||
import com.tangem.feature.swap.models.SwapPermissionState
|
||||
import com.tangem.feature.swap.models.states.GivePermissionBottomSheetConfig
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
fun SwapPermissionBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet(config) { content: GivePermissionBottomSheetConfig ->
|
||||
SwapPermissionBottomSheetContent(content = content)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SwapPermissionBottomSheetContent(content: GivePermissionBottomSheetConfig) {
|
||||
var isPermissionAlertShow by remember { mutableStateOf(false) }
|
||||
val data = content.data
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = stringResource(id = R.string.swapping_permission_header),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
)
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.CenterEnd),
|
||||
onClick = { isPermissionAlertShow = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_question_24),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SpacerH10()
|
||||
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.swapping_permission_subheader,
|
||||
data.currency,
|
||||
),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body2,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing8),
|
||||
)
|
||||
|
||||
SpacerH16()
|
||||
|
||||
ApprovalBottomSheetInfo(data)
|
||||
|
||||
SpacerH28()
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResource(id = R.string.swapping_permission_buttons_approve),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = data.approveButton.onClick,
|
||||
)
|
||||
|
||||
SpacerH12()
|
||||
|
||||
SecondaryButton(
|
||||
text = stringResource(id = R.string.common_cancel),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
content.onCancel()
|
||||
},
|
||||
)
|
||||
|
||||
SpacerH16()
|
||||
|
||||
// region dialog
|
||||
if (isPermissionAlertShow) {
|
||||
BasicDialog(
|
||||
message = stringResource(id = R.string.swapping_approve_information_text),
|
||||
title = stringResource(id = R.string.swapping_approve_information_title),
|
||||
confirmButton = DialogButton { isPermissionAlertShow = false },
|
||||
onDismissDialog = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ApprovalBottomSheetInfo(data: SwapPermissionState.ReadyForRequest) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AmountItem(
|
||||
currency = data.currency,
|
||||
approveType = data.approveType,
|
||||
onChangeApproveType = data.onChangeApproveType,
|
||||
approveItems = data.approveItems,
|
||||
)
|
||||
SubtitleItem(
|
||||
subtitle = stringResource(id = R.string.swapping_permission_policy_type_footer),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
SpacerH24()
|
||||
DividerBottomSheet()
|
||||
FeeItem(fee = data.fee.resolveReference())
|
||||
SubtitleItem(
|
||||
subtitle = stringResource(id = R.string.swapping_permission_fee_footer),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DividerBottomSheet() {
|
||||
Divider(
|
||||
color = TangemTheme.colors.stroke.primary,
|
||||
thickness = TangemTheme.dimens.size0_5,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InformationItem(subtitle: String, value: String) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens.spacing16),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = subtitle,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
||||
MiddleEllipsisText(
|
||||
text = value,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.body2,
|
||||
modifier = Modifier.padding(start = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AmountItem(
|
||||
currency: String,
|
||||
approveType: ApproveType,
|
||||
approveItems: ImmutableList<ApproveType>,
|
||||
onChangeApproveType: (ApproveType) -> Unit,
|
||||
) {
|
||||
var isExpandSelector by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens.spacing16),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.swapping_permission_rows_amount, currency),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
maxLines = 1,
|
||||
)
|
||||
Box {
|
||||
SelectorItem(
|
||||
getTitleForApproveType(approveType = approveType),
|
||||
) {
|
||||
isExpandSelector = true
|
||||
}
|
||||
DropdownSelector(
|
||||
isExpanded = isExpandSelector,
|
||||
onDismiss = { isExpandSelector = false },
|
||||
onItemClick = { approveType ->
|
||||
isExpandSelector = false
|
||||
onChangeApproveType.invoke(approveType)
|
||||
},
|
||||
items = approveItems,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SelectorItem(title: String, onClick: () -> Unit) {
|
||||
Row(
|
||||
modifier = Modifier.clickable { onClick() },
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.body1,
|
||||
maxLines = 1,
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_chevron_24),
|
||||
tint = TangemTheme.colors.icon.primary1,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DropdownSelector(
|
||||
isExpanded: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onItemClick: (ApproveType) -> Unit,
|
||||
items: ImmutableList<ApproveType>,
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = isExpanded,
|
||||
onDismissRequest = onDismiss,
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.background(TangemTheme.colors.background.secondary),
|
||||
) {
|
||||
items.forEach { item ->
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onItemClick.invoke(item)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = getTitleForApproveType(approveType = item),
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.body1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeeItem(fee: String) {
|
||||
InformationItem(
|
||||
subtitle = stringResource(id = R.string.common_network_fee_title),
|
||||
value = fee,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SubtitleItem(subtitle: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = subtitle,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getTitleForApproveType(approveType: ApproveType): String = when (approveType) {
|
||||
ApproveType.LIMITED -> stringResource(id = R.string.swapping_permission_current_transaction)
|
||||
ApproveType.UNLIMITED -> stringResource(id = R.string.swapping_permission_unlimited)
|
||||
}
|
||||
|
||||
// region preview
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview_AgreementBottomSheet() {
|
||||
TangemThemePreview {
|
||||
SwapPermissionBottomSheetContent(content = previewData)
|
||||
}
|
||||
}
|
||||
|
||||
private val previewData = GivePermissionBottomSheetConfig(
|
||||
data = SwapPermissionState.ReadyForRequest(
|
||||
currency = "DAI",
|
||||
amount = "∞",
|
||||
walletAddress = "",
|
||||
spenderAddress = "",
|
||||
fee = TextReference.Str("2,14$"),
|
||||
approveType = ApproveType.UNLIMITED,
|
||||
approveButton = ApprovePermissionButton(true) {},
|
||||
cancelButton = CancelPermissionButton(true),
|
||||
onChangeApproveType = { ApproveType.UNLIMITED },
|
||||
),
|
||||
onCancel = {},
|
||||
)
|
||||
|
|
@ -6,13 +6,14 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.tangem.common.ui.bottomsheets.GiveTxPermissionBottomSheet
|
||||
import com.tangem.common.ui.bottomsheets.state.GiveTxPermissionBottomSheetConfig
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.utils.WindowInsetsZero
|
||||
import com.tangem.feature.swap.models.SwapStateHolder
|
||||
import com.tangem.feature.swap.models.states.ChooseFeeBottomSheetConfig
|
||||
import com.tangem.feature.swap.models.states.ChooseProviderBottomSheetConfig
|
||||
import com.tangem.feature.swap.models.states.GivePermissionBottomSheetConfig
|
||||
import com.tangem.feature.swap.models.states.WebViewBottomSheetConfig
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
|
||||
|
|
@ -40,8 +41,8 @@ internal fun SwapScreen(stateHolder: SwapStateHolder) {
|
|||
|
||||
stateHolder.bottomSheetConfig?.let { config ->
|
||||
when (config.content) {
|
||||
is GivePermissionBottomSheetConfig -> {
|
||||
SwapPermissionBottomSheet(config = config)
|
||||
is GiveTxPermissionBottomSheetConfig -> {
|
||||
GiveTxPermissionBottomSheet(config = config)
|
||||
}
|
||||
is ChooseProviderBottomSheetConfig -> {
|
||||
ChooseProviderBottomSheet(config = config)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import com.tangem.common.ui.bottomsheets.state.GiveTxPermissionState
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
|
|
@ -414,7 +415,7 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U
|
|||
state.warnings.any { it is SwapWarning.PermissionNeeded } -> {
|
||||
PrimaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.swapping_give_permission),
|
||||
text = stringResource(id = R.string.give_permission_title),
|
||||
enabled = true,
|
||||
onClick = onPermissionWarningClick,
|
||||
)
|
||||
|
|
@ -495,7 +496,7 @@ private val state = SwapStateHolder(
|
|||
onRefresh = {},
|
||||
onBackClicked = {},
|
||||
onChangeCardsClicked = {},
|
||||
permissionState = SwapPermissionState.InProgress,
|
||||
permissionState = GiveTxPermissionState.InProgress,
|
||||
blockchainId = "POLYGON",
|
||||
providerState = ProviderState.Loading(),
|
||||
priceImpact = PriceImpact.Empty(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.swap.viewmodels
|
||||
|
||||
import com.tangem.common.ui.bottomsheets.state.ApproveType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapDataModel
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapProvider
|
||||
|
|
@ -7,7 +8,6 @@ import com.tangem.feature.swap.domain.models.ui.RequestApproveStateData
|
|||
import com.tangem.feature.swap.domain.models.ui.SwapState
|
||||
import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress
|
||||
import com.tangem.feature.swap.domain.models.ui.TxFee
|
||||
import com.tangem.feature.swap.models.ApproveType
|
||||
|
||||
data class SwapProcessDataState(
|
||||
// Initial network id
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import arrow.core.Either
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.bundle.unbundle
|
||||
import com.tangem.common.ui.bottomsheets.state.ApproveType
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
|
|
@ -73,7 +74,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
) : ViewModel(), DefaultLifecycleObserver {
|
||||
|
||||
private val initialCryptoCurrency: CryptoCurrency = savedStateHandle.get<Bundle>(AppRoute.Swap.CURRENCY_BUNDLE_KEY)
|
||||
?.let { it.unbundle(CryptoCurrency.serializer()) }
|
||||
?.unbundle(CryptoCurrency.serializer())
|
||||
?: error("no expected parameter CryptoCurrency found`")
|
||||
|
||||
private lateinit var initialCryptoCurrencyStatus: CryptoCurrencyStatus
|
||||
|
|
@ -1173,6 +1174,13 @@ internal class SwapViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun ApproveType.toDomainApproveType(): SwapApproveType {
|
||||
return when (this) {
|
||||
ApproveType.LIMITED -> SwapApproveType.LIMITED
|
||||
ApproveType.UNLIMITED -> SwapApproveType.UNLIMITED
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val loggingTag = "SwapViewModel"
|
||||
const val INITIAL_AMOUNT = ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue