Updated on 2026-08-14

This commit is contained in:
Tangem 2024-01-31 14:05:23 +03:00
parent 0344c98f5f
commit 9cd37f92c5
15 changed files with 148 additions and 143 deletions

View file

@ -63,7 +63,8 @@ internal fun SettingsSwitchItem(item: Item.Switch, modifier: Modifier = Modifier
checked = item.isChecked,
enabled = item.isEnabled,
onCheckedChange = item.onCheckedChange,
checkedColor = TangemTheme.colors.icon.accent,
checkedColor = TangemTheme.colors.control.checked,
uncheckedColor = TangemTheme.colors.icon.inactive,
)
}
}

View file

@ -27,9 +27,9 @@ internal class ResetCardFragment : ComposeFragment(), StoreSubscriber<DetailsSta
@Composable
override fun ScreenContent(modifier: Modifier) {
ResetCardScreen(
modifier = modifier,
state = screenState.value,
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
modifier = modifier,
)
}

View file

@ -1,27 +1,23 @@
package com.tangem.tap.features.details.ui.resetcard
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
import androidx.compose.material.IconToggleButton
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.SpacerH24
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.ScreenTitle
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
import com.tangem.wallet.R
@ -31,9 +27,7 @@ internal fun ResetCardScreen(state: ResetCardScreenState, onBackClick: () -> Uni
modifier = modifier,
content = {
when (state) {
is ResetCardScreenState.ResetCardScreenContent -> {
ResetCardView(state = state)
}
is ResetCardScreenState.ResetCardScreenContent -> ResetCardView(state = state)
ResetCardScreenState.InitialState -> {
// do nothing for now, just white screen
}
@ -43,83 +37,86 @@ internal fun ResetCardScreen(state: ResetCardScreenState, onBackClick: () -> Uni
)
}
@Suppress("LongMethod", "MagicNumber")
@Composable
private fun ResetCardView(state: ResetCardScreenState.ResetCardScreenContent) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.SpaceBetween,
.verticalScroll(scrollState) // set scrollState after fillMaxSize
.padding(horizontal = TangemTheme.dimens.spacing20),
) {
ScreenTitle(titleRes = R.string.card_settings_reset_card_to_factory)
Box(
modifier = Modifier
.weight(1f)
.padding(horizontal = 21.dp),
contentAlignment = Alignment.CenterStart,
) {
Icon(
painter = painterResource(id = R.drawable.img_alert),
contentDescription = "",
tint = Color.Unspecified,
)
}
Column(
modifier = Modifier.offset(y = (-32).dp),
verticalArrangement = Arrangement.Bottom,
) {
Text(
text = stringResource(id = R.string.common_attention),
modifier = Modifier.padding(start = 20.dp, end = 20.dp),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
)
Title()
SpacerH24()
AlertImage()
SpacerH24()
Subtitle()
SpacerH16()
Description(text = state.descriptionText)
SpacerH12()
Conditions(state)
DynamicSpacer(scrollState = scrollState)
SpacerH16()
ResetButton(enabled = state.resetButtonEnabled, onResetButtonClick = state.onResetButtonClick)
SpacerH16()
}
}
Spacer(modifier = Modifier.size(24.dp))
@Composable
private fun Title() {
Text(
text = stringResource(id = R.string.card_settings_reset_card_to_factory),
style = TangemTheme.typography.h1,
color = TangemTheme.colors.text.primary1,
)
}
Text(
text = state.descriptionText.resolveReference(),
modifier = Modifier.padding(start = 20.dp, end = 20.dp),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
)
@Composable
private fun AlertImage() {
Image(
painter = painterResource(id = R.drawable.img_alert_80),
contentDescription = null,
modifier = Modifier.size(TangemTheme.dimens.size80),
)
}
Spacer(modifier = Modifier.size(28.dp))
@Composable
private fun Subtitle() {
Text(
text = stringResource(id = R.string.common_attention),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
)
}
state.warningsToShow.forEach {
when (it) {
ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS -> {
ConditionCheckBox(
checkedState = state.acceptCondition1Checked,
onCheckedChange = state.onAcceptCondition1ToggleClick,
description = TextReference.Res(R.string.reset_card_to_factory_condition_1),
)
}
ResetCardScreenState.WarningsToReset.LOST_PASSWORD_RESTORE -> {
ConditionCheckBox(
checkedState = state.acceptCondition2Checked,
onCheckedChange = state.onAcceptCondition2ToggleClick,
description = TextReference.Res(R.string.reset_card_to_factory_condition_2),
)
}
}
@Composable
private fun Description(text: TextReference) {
Text(
text = text.resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
)
}
@Composable
private fun Conditions(state: ResetCardScreenState.ResetCardScreenContent) {
state.warningsToShow.forEach {
when (it) {
ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS -> {
ConditionCheckBox(
checkedState = state.acceptCondition1Checked,
onCheckedChange = state.onAcceptCondition1ToggleClick,
description = TextReference.Res(R.string.reset_card_to_factory_condition_1),
)
}
Spacer(modifier = Modifier.size(16.dp))
Box(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 32.dp),
) {
AnimatedContent(
targetState = state.resetButtonEnabled,
label = "Update checked state",
) { buttonEnabled ->
DetailsMainButton(
title = stringResource(id = R.string.reset_card_to_factory_button_title),
onClick = state.onResetButtonClick,
enabled = buttonEnabled,
)
}
ResetCardScreenState.WarningsToReset.LOST_PASSWORD_RESTORE -> {
ConditionCheckBox(
checkedState = state.acceptCondition2Checked,
onCheckedChange = state.onAcceptCondition2ToggleClick,
description = TextReference.Res(R.string.reset_card_to_factory_condition_2),
)
}
}
}
@ -130,16 +127,11 @@ private fun ConditionCheckBox(checkedState: Boolean, onCheckedChange: (Boolean)
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(
onClick = { onCheckedChange.invoke(!checkedState) },
)
.padding(top = TangemTheme.dimens.size16, bottom = TangemTheme.dimens.size16),
.clickable(onClick = { onCheckedChange.invoke(!checkedState) })
.padding(vertical = TangemTheme.dimens.size16),
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16),
) {
IconToggleButton(
checked = checkedState,
onCheckedChange = onCheckedChange,
modifier = Modifier.padding(start = TangemTheme.dimens.size20, end = TangemTheme.dimens.size20),
) {
IconToggleButton(checked = checkedState, onCheckedChange = onCheckedChange) {
AnimatedContent(targetState = checkedState, label = "Update checked state") { checked ->
Icon(
painter = painterResource(
@ -151,22 +143,44 @@ private fun ConditionCheckBox(checkedState: Boolean, onCheckedChange: (Boolean)
),
contentDescription = null,
tint = if (checked) {
TangemTheme.colors.icon.accent
TangemTheme.colors.control.checked
} else {
TangemTheme.colors.icon.secondary
},
)
}
}
Text(
text = description.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier.padding(end = TangemTheme.dimens.size20),
)
}
}
/**
* It's helps to create an adaptive layout.
* ResetButton will be attach to the bottom of large screen or will be inside scroll layout of small screen.
*
* @param scrollState flag determines if screen is small (has scroll) or large (hasn't scroll)
*/
@Composable
private fun ColumnScope.DynamicSpacer(scrollState: ScrollState) {
if (!scrollState.canScrollBackward && !scrollState.canScrollForward) {
Spacer(modifier = Modifier.weight(1f))
}
}
@Composable
private fun ResetButton(enabled: Boolean, onResetButtonClick: () -> Unit) {
DetailsMainButton(
title = stringResource(id = R.string.reset_card_to_factory_button_title),
onClick = onResetButtonClick,
enabled = enabled,
)
}
// region Preview
@Composable
private fun ResetCardScreenSample(modifier: Modifier = Modifier) {

View file

@ -655,7 +655,7 @@
<string name="wallet_connect_service_no_chain_id">Dapp не предоставил необходимые данные для открытия сессии WalletConnect</string>
<string name="wallet_connect_session_not_found">Не удалось найти сессию для обработки запроса</string>
<string name="wallet_connect_sessions_title">Сессии WalletConnect</string>
<string name="wallet_connect_subtitle">Подключение к Dapps</string>
<string name="wallet_connect_subtitle">Подключение к dApps</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_transaction_signed">Транзакция успешно подписана и отправлена ​​в Dapp</string>
<string name="wallet_connect_transaction_signed_and_send">Транзакция успешно подписана и отправлена ​​в блокчейн</string>

View file

@ -425,7 +425,7 @@
<string name="wallet_connect_service_no_chain_id">Dapp 沒有提供必要的數據來建立 WalletConnect 連接</string>
<string name="wallet_connect_session_not_found">找不到請求的連接</string>
<string name="wallet_connect_sessions_title">WalletConnect 連接</string>
<string name="wallet_connect_subtitle">連結到Dapps</string>
<string name="wallet_connect_subtitle">連結到dApps</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_transaction_signed">交易已成功簽署並發送至 Dapp</string>
<string name="wallet_connect_transaction_signed_and_send">交易已成功簽署並發送至區塊鏈</string>

View file

@ -671,7 +671,7 @@
<string name="wallet_connect_service_no_chain_id">Dapp didn\'t provide essential data to establish WalletConnect session</string>
<string name="wallet_connect_session_not_found">Failed to find session for request</string>
<string name="wallet_connect_sessions_title">WalletConnect Sessions</string>
<string name="wallet_connect_subtitle">Connect to Dapps</string>
<string name="wallet_connect_subtitle">Connect to dApps</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_transaction_signed">The transaction has been successfully signed and sent to the Dapp</string>
<string name="wallet_connect_transaction_signed_and_send">The transaction has been succesfully signed and sent to the blockchain</string>

View file

@ -7,7 +7,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.*
import androidx.compose.material.RadioButton
import androidx.compose.material.RadioButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
@ -210,7 +212,7 @@ private fun TangemDialog(
modifier = Modifier
.background(
shape = TangemTheme.shapes.roundedCornersLarge,
color = TangemTheme.colors.background.plain,
color = TangemTheme.colors.background.primary,
)
.padding(vertical = TangemTheme.dimens.spacing24),
) {
@ -386,7 +388,7 @@ private fun SelectorDialogContent(
selected = index == selectedItemIndex,
onClick = onClick,
colors = RadioButtonDefaults.colors(
selectedColor = TangemTheme.colors.icon.accent,
selectedColor = TangemTheme.colors.control.checked,
unselectedColor = TangemTheme.colors.icon.secondary,
),
interactionSource = interactionSource,

View file

@ -42,7 +42,7 @@ class TangemColors internal constructor(
warning: Color,
attention: Color,
accent: Color = TangemColorPalette.Azure,
constantWhite: Color = TangemColorPalette.White,
constant: Color = TangemColorPalette.White,
) {
var primary1 by mutableStateOf(primary1)
private set
@ -60,7 +60,7 @@ class TangemColors internal constructor(
private set
var attention by mutableStateOf(attention)
private set
var constantWhite by mutableStateOf(constantWhite)
var constantWhite by mutableStateOf(constant)
private set
fun update(other: Text) {
@ -83,6 +83,7 @@ class TangemColors internal constructor(
warning: Color,
attention: Color,
accent: Color = TangemColorPalette.Azure,
constant: Color = TangemColorPalette.White,
) {
var primary1 by mutableStateOf(primary1)
private set
@ -118,8 +119,7 @@ class TangemColors internal constructor(
primary: Color,
secondary: Color,
disabled: Color,
positive: Color = TangemColorPalette.Meadow,
positiveDisabled: Color,
positive: Color = TangemColorPalette.Azure,
) {
var primary by mutableStateOf(primary)
private set
@ -129,15 +129,12 @@ class TangemColors internal constructor(
private set
var positive by mutableStateOf(positive)
private set
var positiveDisabled by mutableStateOf(positiveDisabled)
private set
fun update(other: Button) {
primary = other.primary
secondary = other.secondary
disabled = other.disabled
positive = other.positive
positiveDisabled = other.positiveDisabled
}
}
@ -146,9 +143,7 @@ class TangemColors internal constructor(
primary: Color,
secondary: Color,
tertiary: Color,
plain: Color,
action: Color,
fade: Color,
) {
var primary by mutableStateOf(primary)
private set
@ -156,20 +151,14 @@ class TangemColors internal constructor(
private set
var tertiary by mutableStateOf(tertiary)
private set
var plain by mutableStateOf(plain)
private set
var action by mutableStateOf(action)
private set
var fade by mutableStateOf(fade)
private set
fun update(other: Background) {
primary = other.primary
secondary = other.secondary
tertiary = other.tertiary
plain = other.plain
action = other.action
fade = other.fade
}
}

View file

@ -51,6 +51,7 @@ data class TangemDimens internal constructor(
val size11: Dp = 11.dp,
val size12: Dp = 12.dp,
val size14: Dp = 14.dp,
val size15: Dp = 15.dp,
val size16: Dp = 16.dp,
val size18: Dp = 18.dp,
val size20: Dp = 20.dp,

View file

@ -69,7 +69,7 @@ private fun materialThemeColors(colors: TangemColors, isDark: Boolean): Colors {
secondary = colors.button.primary,
secondaryVariant = colors.text.accent,
background = colors.background.primary,
surface = colors.background.plain,
surface = colors.background.secondary,
error = colors.text.warning,
onPrimary = colors.text.primary1,
onSecondary = colors.text.primary1,
@ -94,10 +94,10 @@ private fun lightThemeColors(): TangemColors {
attention = TangemColorPalette.Tangerine,
),
icon = TangemColors.Icon(
primary1 = TangemColorPalette.Black,
primary1 = TangemColorPalette.Dark6,
primary2 = TangemColorPalette.White,
secondary = TangemColorPalette.Dark2,
informative = TangemColorPalette.Light5,
informative = TangemColorPalette.Dark1,
inactive = TangemColorPalette.Light4,
warning = TangemColorPalette.Amaranth,
attention = TangemColorPalette.Tangerine,
@ -106,15 +106,12 @@ private fun lightThemeColors(): TangemColors {
primary = TangemColorPalette.Dark6,
secondary = TangemColorPalette.Light2,
disabled = TangemColorPalette.Light2,
positiveDisabled = TangemColorPalette.MagicMint,
),
background = TangemColors.Background(
primary = TangemColorPalette.White,
secondary = TangemColorPalette.Light1,
tertiary = TangemColorPalette.Light1,
plain = TangemColorPalette.White,
action = TangemColorPalette.White,
fade = TangemColorPalette.White,
),
control = TangemColors.Control(
checked = TangemColorPalette.Dark6,
@ -123,7 +120,7 @@ private fun lightThemeColors(): TangemColors {
),
stroke = TangemColors.Stroke(
primary = TangemColorPalette.Light2,
secondary = TangemColorPalette.Dark4,
secondary = TangemColorPalette.Dark5,
transparency = TangemColorPalette.White,
),
field = TangemColors.Field(
@ -149,25 +146,22 @@ private fun darkThemeColors(): TangemColors {
icon = TangemColors.Icon(
primary1 = TangemColorPalette.White,
primary2 = TangemColorPalette.Dark6,
secondary = TangemColorPalette.Dark1,
informative = TangemColorPalette.Dark2,
inactive = TangemColorPalette.Dark4,
secondary = TangemColorPalette.Light5,
informative = TangemColorPalette.Dark1,
inactive = TangemColorPalette.Dark3,
warning = TangemColorPalette.Flamingo,
attention = TangemColorPalette.Mustard,
),
button = TangemColors.Button(
primary = TangemColorPalette.Light4,
primary = TangemColorPalette.Light2,
secondary = TangemColorPalette.Dark4,
disabled = TangemColorPalette.Dark5,
positiveDisabled = TangemColorPalette.DarkGreen,
),
background = TangemColors.Background(
primary = TangemColorPalette.Dark6,
secondary = TangemColorPalette.Black,
tertiary = TangemColorPalette.Dark6,
plain = TangemColorPalette.Black,
action = TangemColorPalette.Dark5,
fade = TangemColorPalette.Black,
),
control = TangemColors.Control(
checked = TangemColorPalette.Azure,
@ -176,7 +170,7 @@ private fun darkThemeColors(): TangemColors {
),
stroke = TangemColors.Stroke(
primary = TangemColorPalette.Dark4,
secondary = TangemColorPalette.Dark1,
secondary = TangemColorPalette.Dark4,
transparency = TangemColorPalette.Dark6,
),
field = TangemColors.Field(

View file

@ -78,7 +78,7 @@ data class TangemTypography internal constructor(
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
letterSpacing = TextUnit(value = 0.1f, type = TextUnitType.Sp),
lineHeight = TextUnit(value = 20f, type = TextUnitType.Sp),
lineHeight = TextUnit(value = 16f, type = TextUnitType.Sp),
),
val caption1: TextStyle = TextStyle(
fontFamily = RobotoFamily,

View file

@ -45,7 +45,7 @@ abstract class ComposeBottomSheetFragment : BottomSheetDialogFragment(), Compose
if (expandedHeightFraction != null) it.fillMaxHeight(expandedHeightFraction!!) else it
}
.background(
color = TangemTheme.colors.background.plain,
color = TangemTheme.colors.background.primary,
shape = TangemTheme.shapes.bottomSheet,
)

View file

@ -280,7 +280,7 @@ private fun SwapButton(state: SwapStateHolder, modifier: Modifier = Modifier) {
Card(
elevation = TangemTheme.dimens.elevation3,
shape = CircleShape,
backgroundColor = TangemTheme.colors.background.plain,
backgroundColor = TangemTheme.colors.background.action,
contentColor = TangemTheme.colors.text.primary1,
modifier = modifier.size(TangemTheme.dimens.size48),
onClick = state.onChangeCardsClicked,

View file

@ -7,7 +7,10 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.layout.*
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -123,8 +126,9 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
Layout(content = content, modifier = modifier) { measurables, constraints ->
val layoutWidth = constraints.maxWidth
val layoutPadding = with(density) { dimens.size14.roundToPx() }
val layoutWidthWithoutPaddings = layoutWidth - 2 * layoutPadding
val horizontalPadding = with(density) { dimens.size14.roundToPx() }
val verticalPadding = with(density) { dimens.size15.roundToPx() }
val layoutWidthWithoutPaddings = layoutWidth - 2 * horizontalPadding
val titleMinWidth = (layoutWidth * TITLE_MIN_WIDTH_COEFFICIENT).toInt()
val priceChangeMinWidth = (layoutWidth * PRICE_MIN_WIDTH_COEFFICIENT).toInt()
@ -209,7 +213,7 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
val layoutHeight = calculateLayoutHeight(
state = state,
minLayoutHeight = with(density) { dimens.size68.roundToPx() },
layoutPadding = layoutPadding,
layoutPadding = horizontalPadding,
betweenRowsPadding = with(density) { dimens.size2.roundToPx() },
title = title,
fiatAmount = fiatAmount,
@ -218,35 +222,35 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
)
layout(width = constraints.maxWidth, height = layoutHeight) {
icon.placeRelative(x = layoutPadding, y = (layoutHeight - icon.height).div(other = 2))
icon.placeRelative(x = horizontalPadding, y = (layoutHeight - icon.height).div(other = 2))
title.placeRelative(
x = layoutPadding + icon.width,
x = horizontalPadding + icon.width,
y = when (state) {
is TokenItemState.NoAddress,
is TokenItemState.Unreachable,
-> (layoutHeight - title.height).div(other = 2)
else -> layoutPadding
else -> verticalPadding
},
)
fiatAmount?.placeRelative(x = layoutWidth - fiatAmount.width - layoutPadding, y = layoutPadding)
fiatAmount?.placeRelative(x = layoutWidth - fiatAmount.width - horizontalPadding, y = verticalPadding)
priceChange?.placeRelative(
x = layoutPadding + icon.width,
y = layoutHeight - priceChange.height - layoutPadding,
x = horizontalPadding + icon.width,
y = layoutHeight - priceChange.height - verticalPadding,
)
cryptoAmount?.placeRelative(
x = when (state) {
is TokenItemState.Draggable -> layoutPadding + icon.width
else -> layoutWidth - cryptoAmount.width - layoutPadding
is TokenItemState.Draggable -> horizontalPadding + icon.width
else -> layoutWidth - cryptoAmount.width - horizontalPadding
},
y = layoutHeight - cryptoAmount.height - layoutPadding,
y = layoutHeight - cryptoAmount.height - verticalPadding,
)
nonFiatContent.placeRelative(
x = layoutWidth - nonFiatContent.width - layoutPadding,
x = layoutWidth - nonFiatContent.width - horizontalPadding,
y = (layoutHeight - nonFiatContent.height).div(other = 2),
)
}