Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-30 16:48:26 +03:00
parent acf110dbcc
commit 6910f74fd9
242 changed files with 866 additions and 732 deletions

View file

@ -178,14 +178,14 @@ fun SelectorDialog(
* Dialog button params
*
* @param title Button text. If not provided default values will be used
* @param warning If true then button text will be in theme warning color
* @param enabled If false button will be disabled
* @param isWarning If true then button text will be in theme warning color
* @param isEnabled If false button will be disabled
* @param onClick Button click callback
*/
data class DialogButtonUM(
val title: String? = null,
val warning: Boolean = false,
val enabled: Boolean = true,
val isWarning: Boolean = false,
val isEnabled: Boolean = true,
val onClick: () -> Unit,
)
@ -196,7 +196,7 @@ data class AdditionalTextInputDialogUM(
val label: String? = null,
val placeholder: String? = null,
val caption: String? = null,
val enabled: Boolean = true,
val isEnabled: Boolean = true,
val isError: Boolean = false,
val errorText: String? = null,
)
@ -276,7 +276,7 @@ private fun DialogContent(type: DialogType, modifier: Modifier = Modifier) {
onValueChange = type.onValueChange,
isError = type.params.isError,
errorText = type.params.errorText,
isEnabled = type.params.enabled,
isEnabled = type.params.isEnabled,
placeholder = type.params.placeholder,
)
}
@ -289,7 +289,7 @@ private fun DialogContent(type: DialogType, modifier: Modifier = Modifier) {
label = type.params.label,
placeholder = type.params.placeholder,
caption = type.params.caption,
enabled = type.params.enabled,
enabled = type.params.isEnabled,
isError = type.params.isError,
onValueChange = { newValue ->
type.onValueChange(newValue)
@ -324,15 +324,15 @@ private fun DialogButtons(
if (dismissButton != null) {
DialogButton(
text = dismissButton.title ?: stringResourceSafe(id = R.string.common_cancel),
warning = dismissButton.warning,
enabled = dismissButton.enabled,
warning = dismissButton.isWarning,
enabled = dismissButton.isEnabled,
onClick = dismissButton.onClick,
)
}
DialogButton(
text = confirmButton.title ?: stringResourceSafe(id = R.string.common_ok),
warning = confirmButton.warning,
enabled = confirmButton.enabled,
warning = confirmButton.isWarning,
enabled = confirmButton.isEnabled,
onClick = confirmButton.onClick,
)
}
@ -487,7 +487,7 @@ private fun WarningBasicDialogSample(modifier: Modifier = Modifier) {
message = "All protected passwords will be deleted from the secure storage, you must enter the wallet " +
"password to work with the app",
title = "Attention",
confirmButton = DialogButtonUM(warning = true) {},
confirmButton = DialogButtonUM(isWarning = true) {},
dismissButton = DialogButtonUM {},
onDismissDialog = {},
)

View file

@ -29,10 +29,10 @@ fun Modifier.edgeFade(
require(value = size > 0.dp) {
"Size must be greater than '0'"
}
val animatedSize = animationSpec?.let {
val animatedSize = animationSpec?.let { spec ->
animateDpAsState(
targetValue = if (isVisible) size else 0.dp,
animationSpec = it,
animationSpec = spec,
label = "Edge fade width",
)
}

View file

@ -29,22 +29,22 @@ fun Modifier.flicker(
targetTextAlpha: Float = 0.4f,
animationDurationMillis: Int = 1500,
): Modifier = composed {
var alphaChange by remember { mutableStateOf(false) }
var shouldAlphaChange by remember { mutableStateOf(false) }
val alpha: Float by animateFloatAsState(
targetValue = if (alphaChange) targetTextAlpha else 1f,
targetValue = if (shouldAlphaChange) targetTextAlpha else 1f,
animationSpec = tween(
durationMillis = animationDurationMillis,
easing = CubicBezierEasing(a = 0.45f, b = 0.0f, c = 0.55f, d = 1.0f),
),
finishedListener = {
alphaChange = it == 1f && isFlickering
shouldAlphaChange = it == 1f && isFlickering
},
)
LaunchedEffect(isFlickering) {
if (isFlickering) {
alphaChange = true
shouldAlphaChange = true
}
}

View file

@ -33,7 +33,7 @@ fun FullScreen(
val fullScreenLayout = remember {
FullScreenLayout(
notTouchable = notTouchable,
isNotTouchable = notTouchable,
focusable = focusable,
composeView = view,
onBackClick = onBackClick,
@ -53,7 +53,7 @@ fun FullScreen(
@SuppressLint("ViewConstructor", "ClickableViewAccessibility")
private class FullScreenLayout(
private val notTouchable: Boolean,
private val isNotTouchable: Boolean,
private val focusable: Boolean,
private val composeView: View,
private val onBackClick: () -> Unit,
@ -68,10 +68,10 @@ private class FullScreenLayout(
override var shouldCreateCompositionOnAttachedToWindow: Boolean = false
private set
private var viewShowing = false
private var isViewShowing = false
init {
if (notTouchable) {
if (isNotTouchable) {
setOnTouchListener { _, _ -> false }
}
@ -110,19 +110,19 @@ private class FullScreenLayout(
}
fun show() {
if (viewShowing) dismiss()
if (isViewShowing) dismiss()
windowManager.addView(this, params)
if (focusable.not()) {
params.flags = params.flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
}
if (notTouchable) {
if (isNotTouchable) {
params.flags = params.flags or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
}
windowManager.updateViewLayout(this, params)
viewShowing = true
isViewShowing = true
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@ -139,10 +139,10 @@ private class FullScreenLayout(
}
fun dismiss() {
if (!viewShowing) return
if (!isViewShowing) return
disposeComposition()
windowManager.removeViewImmediate(this)
viewShowing = false
isViewShowing = false
}
fun dispose() {

View file

@ -38,12 +38,12 @@ fun keyboardAsState(): State<Keyboard> {
val keyboardState = remember { mutableStateOf(keyboardStateInternal) }
LaunchedEffect(keyboardStateInternal) {
val falsePositive = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q &&
val isFalsePositive = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q &&
keyboardStateInternal is Keyboard.Opened &&
keyboardStateInternal.height < 50.dp
// FIX android <=10 devices can randomly send ime paddings,
// which leads to a false positive keyboard opening ([REDACTED_TASK_KEY])
if (falsePositive) return@LaunchedEffect
if (isFalsePositive) return@LaunchedEffect
keyboardState.value = keyboardStateInternal
}

View file

@ -45,8 +45,8 @@ fun ResizableText(
overflow = overflow,
softWrap = false,
maxLines = maxLines,
onTextLayout = {
if (it.hasVisualOverflow) {
onTextLayout = { textLayoutResult ->
if (textLayoutResult.hasVisualOverflow) {
val nextFontSizeValue = fontSizeValue.floatValue - fontSizeRange.step.value
if (nextFontSizeValue <= fontSizeRange.min.value) {
fontSizeValue.floatValue = fontSizeRange.min.value
@ -150,8 +150,8 @@ fun ResizableText(
overflow = overflow,
softWrap = false,
maxLines = maxLines,
onTextLayout = {
if (it.hasVisualOverflow) {
onTextLayout = { result ->
if (result.hasVisualOverflow) {
val nextFontSizeValue = fontSizeValue.value - fontSizeRange.step.value
if (nextFontSizeValue <= fontSizeRange.min.value) {
onFontSizeChange(fontSizeRange.min.value)

View file

@ -66,7 +66,7 @@ fun SimpleSettingsRow(
visible = !subtitle.isNullOrEmpty(),
) {
Text(
text = subtitle ?: "",
text = subtitle.orEmpty(),
style = TangemTheme.typography.body2,
color = rowColors.subtitleColor(enabled = enabled).value,
)

View file

@ -169,17 +169,17 @@ private val TangemShimmerColors: List<Color>
return buildList {
if (isInDarkTheme) {
TangemColorPalette.Dark3.let(::add)
TangemColorPalette.Dark4.let(::add)
TangemColorPalette.Dark6.let(::add)
TangemColorPalette.Dark4.let(::add)
TangemColorPalette.Dark3.let(::add)
add(TangemColorPalette.Dark3)
add(TangemColorPalette.Dark4)
add(TangemColorPalette.Dark6)
add(TangemColorPalette.Dark4)
add(TangemColorPalette.Dark3)
} else {
TangemColorPalette.Light2.let(::add)
TangemColorPalette.Light1.let(::add)
TangemColorPalette.White.let(::add)
TangemColorPalette.Light1.let(::add)
TangemColorPalette.Light2.let(::add)
add(TangemColorPalette.Light2)
add(TangemColorPalette.Light1)
add(TangemColorPalette.White)
add(TangemColorPalette.Light1)
add(TangemColorPalette.Light2)
}
}
}

View file

@ -148,8 +148,8 @@ private fun TangemTextField(
text = label,
style = TangemTheme.typography.caption2,
color = colors.labelColor(
enabled = enabled,
error = isError,
isEnabled = enabled,
isError = isError,
interactionSource = interactionSource,
).value,
)
@ -174,7 +174,7 @@ private fun TangemTextField(
null
},
)
if (iconRes != null) {
iconRes?.let { iconRes ->
IconButton(
modifier = Modifier.size(32.dp),
onClick = onClear,
@ -182,7 +182,7 @@ private fun TangemTextField(
) {
Icon(
modifier = Modifier.size(24.dp),
painter = painterResource(id = iconRes!!),
painter = painterResource(id = iconRes),
tint = colors.trailingIconColor(enabled = enabled, isError = isError).value,
contentDescription = "Clear input",
)
@ -259,8 +259,8 @@ private fun TangemTextFieldWithIcon(
text = label,
style = TangemTheme.typography.caption2,
color = colors.labelColor(
enabled = enabled,
error = isError,
isEnabled = enabled,
isError = isError,
interactionSource = interactionSource,
).value,
)
@ -399,19 +399,19 @@ fun TextFieldColors.trailingIconColor(enabled: Boolean, isError: Boolean): State
@Composable
fun TextFieldColors.indicatorColor(
enabled: Boolean,
isEnabled: Boolean,
isError: Boolean,
interactionSource: InteractionSource,
): State<Color> {
val focused by interactionSource.collectIsFocusedAsState()
val isFocused by interactionSource.collectIsFocusedAsState()
val targetValue = when {
!enabled -> disabledIndicatorColor
!isEnabled -> disabledIndicatorColor
isError -> errorIndicatorColor
focused -> focusedIndicatorColor
isFocused -> focusedIndicatorColor
else -> unfocusedIndicatorColor
}
return if (enabled) {
return if (isEnabled) {
animateColorAsState(
targetValue = targetValue,
animationSpec = tween(durationMillis = 120),
@ -428,13 +428,17 @@ fun TextFieldColors.placeholderColor(enabled: Boolean): State<Color> {
}
@Composable
fun TextFieldColors.labelColor(enabled: Boolean, error: Boolean, interactionSource: InteractionSource): State<Color> {
val focused by interactionSource.collectIsFocusedAsState()
fun TextFieldColors.labelColor(
isEnabled: Boolean,
isError: Boolean,
interactionSource: InteractionSource,
): State<Color> {
val isFocused by interactionSource.collectIsFocusedAsState()
val targetValue = when {
!enabled -> disabledLabelColor
error -> errorLabelColor
focused -> focusedLabelColor
!isEnabled -> disabledLabelColor
isError -> errorLabelColor
isFocused -> focusedLabelColor
else -> unfocusedLabelColor
}
return rememberUpdatedState(targetValue)

View file

@ -146,7 +146,7 @@ private fun SubtitleView(subtitle: String, icon: Painter?) {
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
verticalAlignment = Alignment.CenterVertically,
) {
icon?.let {
icon?.let { icon ->
Image(
painter = icon,
contentDescription = null,
@ -202,9 +202,9 @@ private fun ExpandedSearchView(
}
TextField(
value = textFieldValue,
onValueChange = {
textFieldValue = it
onSearchChange(it.text)
onValueChange = { value ->
textFieldValue = value
onSearchChange(value.text)
},
singleLine = true,
modifier = Modifier

View file

@ -21,7 +21,7 @@ fun TopAppBarButton(button: TopAppBarButtonUM, tint: Color, modifier: Modifier =
when (button) {
is TopAppBarButtonUM.Icon -> {
IconButton(
enabled = button.enabled,
enabled = button.isEnabled,
modifier = modifier.size(TangemTheme.dimens.size32),
onClick = button.onClicked,
) {
@ -36,7 +36,7 @@ fun TopAppBarButton(button: TopAppBarButtonUM, tint: Color, modifier: Modifier =
is TopAppBarButtonUM.Text -> {
Text(
modifier = modifier
.conditional(button.enabled) {
.conditional(button.isEnabled) {
clickable { button.onClicked() }
}
.padding(4.dp),

View file

@ -6,20 +6,20 @@ import com.tangem.core.ui.extensions.TextReference
sealed class TopAppBarButtonUM(
open val onClicked: () -> Unit,
open val enabled: Boolean = true,
open val isEnabled: Boolean = true,
) {
data class Icon(
@DrawableRes val iconRes: Int,
override val onClicked: () -> Unit,
override val enabled: Boolean = true,
) : TopAppBarButtonUM(onClicked, enabled)
override val isEnabled: Boolean = true,
) : TopAppBarButtonUM(onClicked, isEnabled)
data class Text(
val text: TextReference,
override val onClicked: () -> Unit,
override val enabled: Boolean = true,
) : TopAppBarButtonUM(onClicked, enabled)
override val isEnabled: Boolean = true,
) : TopAppBarButtonUM(onClicked, isEnabled)
@Suppress("FunctionName")
companion object {
@ -29,19 +29,19 @@ sealed class TopAppBarButtonUM(
fun Back(enabled: Boolean = true, onBackClicked: () -> Unit) = Icon(
iconRes = R.drawable.ic_back_24,
onClicked = onBackClicked,
enabled = enabled,
isEnabled = enabled,
)
fun Close(enabled: Boolean = true, onCloseClick: () -> Unit) = Icon(
iconRes = R.drawable.ic_close_24,
onClicked = onCloseClick,
enabled = enabled,
isEnabled = enabled,
)
fun Text(text: TextReference, onTextClicked: () -> Unit, enabled: Boolean = true) = Text(
text = text,
onClicked = onTextClicked,
enabled = enabled,
isEnabled = enabled,
)
}
}

View file

@ -50,8 +50,11 @@ fun ModalBottomSheetWithBackHandling(
modifier = modifier
.focusRequester(requester)
.focusable()
.onPreviewKeyEvent {
if (it.key == Key.Back && it.type == KeyEventType.KeyUp && !it.nativeKeyEvent.isCanceled) {
.onPreviewKeyEvent { keyEvent ->
if (keyEvent.key == Key.Back &&
keyEvent.type == KeyEventType.KeyUp &&
!keyEvent.nativeKeyEvent.isCanceled
) {
backPressedDispatcherOwner?.onBackPressedDispatcher?.onBackPressed()
return@onPreviewKeyEvent true
}

View file

@ -84,7 +84,7 @@ internal fun Content(model: MessageBottomSheetUM, modifier: Modifier = Modifier)
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
text = model.primaryAction.text.resolveReference(),
enabled = model.primaryAction.enabled,
enabled = model.primaryAction.isEnabled,
onClick = model.primaryAction.onClick,
)
}
@ -93,7 +93,7 @@ internal fun Content(model: MessageBottomSheetUM, modifier: Modifier = Modifier)
SecondaryButton(
modifier = Modifier.fillMaxWidth(),
text = model.secondaryAction.text.resolveReference(),
enabled = model.secondaryAction.enabled,
enabled = model.secondaryAction.isEnabled,
onClick = model.secondaryAction.onClick,
)
}

View file

@ -14,7 +14,7 @@ data class MessageBottomSheetUM(
data class ActionUM(
val text: TextReference,
val enabled: Boolean = true,
val isEnabled: Boolean = true,
val onClick: () -> Unit,
)
}

View file

@ -64,8 +64,8 @@ fun MessageBottomSheetV2(state: MessageBottomSheetUMV2, onDismissRequest: () ->
@Composable
fun MessageBottomSheetV2Content(state: MessageBottomSheetUMV2, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
state.elements.fastForEach {
when (it) {
state.elements.fastForEach { element ->
when (element) {
is MessageBottomSheetUMV2.InfoBlock -> {
ContentContainer(
modifier = Modifier
@ -73,7 +73,7 @@ fun MessageBottomSheetV2Content(state: MessageBottomSheetUMV2, modifier: Modifie
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing16)
.padding(bottom = 32.dp),
state = it,
state = element,
)
}
else -> Unit
@ -94,32 +94,32 @@ private fun ContentContainer(state: MessageBottomSheetUMV2.InfoBlock, modifier:
state.icon?.let {
BottomSheetIcon(it)
}
state.title?.let {
state.title?.let { title ->
Text(
modifier = Modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens.spacing24),
text = it.resolveReference(),
text = title.resolveReference(),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
)
}
state.body?.let {
state.body?.let { body ->
Text(
modifier = Modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens.spacing8),
text = it.resolveReference(),
text = body.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
)
}
state.chip?.let {
state.chip?.let { chip ->
BottomSheetChip(
modifier = Modifier.padding(top = TangemTheme.dimens.spacing16),
chip = it,
chip = chip,
)
}
}
@ -193,16 +193,16 @@ private fun ButtonsContainer(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
buttons.fastForEach { button ->
val icon = button.icon?.let {
val icon = button.icon?.let { iconResId ->
when (button.iconOrder) {
IconOrder.Start -> TangemButtonIconPosition.Start(it)
IconOrder.End -> TangemButtonIconPosition.End(it)
IconOrder.Start -> TangemButtonIconPosition.Start(iconResId)
IconOrder.End -> TangemButtonIconPosition.End(iconResId)
}
} ?: TangemButtonIconPosition.None
TangemButton(
modifier = Modifier.fillMaxWidth(),
text = button.text?.resolveReference() ?: "",
text = button.text?.resolveReference().orEmpty(),
icon = icon,
onClick = { button.onClick?.invoke(closeScope) },
colors = if (button.isPrimary) {

View file

@ -95,9 +95,10 @@ inline fun <reified T : TangemBottomSheetConfigContent> DefaultModalBottomSheet(
var isVisible by remember { mutableStateOf(value = config.isShown) }
val sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = skipPartiallyExpanded,
confirmValueChange = {
confirmValueChange = { sheetValue ->
if (!dismissOnClickOutside) {
it != SheetValue.Hidden // Ignore transitions to hidden (prevents dismiss on outside click/back press)
// Ignore transitions to hidden (prevents dismiss on outside click/back press)
sheetValue != SheetValue.Hidden
} else {
true
}

View file

@ -163,11 +163,11 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicBottomSheet(
val bsContent: @Composable ColumnScope.() -> Unit = {
Column(
modifier = Modifier.let {
modifier = Modifier.let { modifier ->
if (addBottomInsets) {
it.padding(bottom = bottomBarHeight)
modifier.padding(bottom = bottomBarHeight)
} else {
it
modifier
}
},
) {

View file

@ -77,7 +77,7 @@ private class ActionButtonConfigProvider : CollectionPreviewParameterProvider<Ho
text = TextReference.Str(value = "Exchange"),
iconResId = R.drawable.ic_exchange_vertical_24,
onClick = {},
showBadge = true,
shouldShowBadge = true,
),
ActionButtonConfig(
text = TextReference.Str(value = "Send"),

View file

@ -33,7 +33,7 @@ data class SmallButtonConfig(
val text: TextReference,
val onClick: () -> Unit,
val icon: TangemButtonIconPosition = TangemButtonIconPosition.None,
val enabled: Boolean = true,
val isEnabled: Boolean = true,
)
/**
@ -79,7 +79,7 @@ private fun SmallButton(config: SmallButtonConfig, isPrimary: Boolean, modifier:
color = backgroundColor,
shape = shape,
)
.clickable(enabled = config.enabled, onClick = config.onClick)
.clickable(enabled = config.isEnabled, onClick = config.onClick)
.padding(
paddingValues = when (config.icon) {
is TangemButtonIconPosition.None -> PaddingValues(
@ -103,7 +103,7 @@ private fun SmallButton(config: SmallButtonConfig, isPrimary: Boolean, modifier:
text = {
val textColor by animateColorAsState(
targetValue = when {
!config.enabled -> TangemTheme.colors.text.disabled
!config.isEnabled -> TangemTheme.colors.text.disabled
isPrimary -> TangemTheme.colors.text.primary2
else -> TangemTheme.colors.text.primary1
},
@ -122,7 +122,7 @@ private fun SmallButton(config: SmallButtonConfig, isPrimary: Boolean, modifier:
Icon(
modifier = Modifier.size(TangemTheme.dimens.size16),
painter = painterResource(id = iconResId),
tint = if (config.enabled) {
tint = if (config.isEnabled) {
TangemTheme.colors.icon.secondary
} else {
TangemTheme.colors.icon.inactive
@ -188,7 +188,7 @@ private fun ButtonsSample() {
config = config.copy(
text = TextReference.Str(value = "Add token"),
icon = TangemButtonIconPosition.Start(iconResId = R.drawable.ic_plus_24),
enabled = false,
isEnabled = false,
),
)
}

View file

@ -6,15 +6,14 @@ import com.tangem.core.ui.extensions.TextReference
/**
* Action button config
*
* @property text text
* @property iconResId icon resource id
* @property onClick lambda be invoked when action component is clicked
* @property onLongClick lambda be invoked when action component is long clicked
* @property enabled enabled
* @property dimContent determines whether the button content will be dimmed. This property will be ignored if [enabled]
* is `false`.
* @property isInProgress indicates progress state of button
* @property showBadge display dot in upper right corner
* @property text text
* @property iconResId icon resource id
* @property onClick lambda be invoked when action component is clicked
* @property onLongClick lambda be invoked when action component is long clicked
* @property isEnabled enabled
* @property shouldDimContent determines whether the button content will be dimmed. This property will be ignored if [isEnabled] is `false`.
* @property isInProgress indicates progress state of button
* @property shouldShowBadge display dot in upper right corner
*
[REDACTED_AUTHOR]
*/
@ -23,8 +22,8 @@ data class ActionButtonConfig(
@DrawableRes val iconResId: Int,
val onClick: () -> Unit,
val onLongClick: (() -> TextReference?)? = null,
val enabled: Boolean = true,
val dimContent: Boolean = false,
val isEnabled: Boolean = true,
val shouldDimContent: Boolean = false,
val isInProgress: Boolean = false,
val showBadge: Boolean = false,
val shouldShowBadge: Boolean = false,
)

View file

@ -55,11 +55,11 @@ fun RoundedActionButton(
ActionBaseButton(
config = config,
shape = RoundedCornerShape(size = TangemTheme.dimens.radius24),
content = {
content = { modifier ->
ActionButtonContent(
config = config,
text = { Text(text = config.text, textColor = it) },
modifier = it.padding(
text = { color -> Text(text = config.text, textColor = color) },
modifier = modifier.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing24,
),
@ -118,7 +118,7 @@ fun ActionBaseButton(
) {
val context = LocalContext.current
val backgroundColor by animateColorAsState(
targetValue = if (config.enabled) color else TangemTheme.colors.button.disabled,
targetValue = if (config.isEnabled) color else TangemTheme.colors.button.disabled,
label = "Update background color",
)
@ -128,17 +128,17 @@ fun ActionBaseButton(
.widthIn(min = 100.dp)
.drawWithContent {
drawContent()
if (config.showBadge) {
if (config.shouldShowBadge) {
drawBadge(containerColor = containerColor)
}
}
.clip(shape)
.combinedClickable(
enabled = config.enabled,
enabled = config.isEnabled,
onClick = config.onClick,
onLongClick = {
val toastReference = config.onLongClick?.invoke()
toastReference?.let {
toastReference?.let { toastReference ->
Toast
.makeText(context, toastReference.resolveReference(context.resources), Toast.LENGTH_SHORT)
.show()
@ -175,8 +175,8 @@ fun ActionButtonContent(
verticalAlignment = Alignment.CenterVertically,
) {
val iconTint = when {
!config.enabled -> TangemTheme.colors.icon.informative
config.dimContent -> TangemTheme.colors.icon.informative
!config.isEnabled -> TangemTheme.colors.icon.informative
config.shouldDimContent -> TangemTheme.colors.icon.informative
else -> TangemTheme.colors.icon.primary1
}
Icon(
@ -220,8 +220,8 @@ private fun Loading(backgroundColor: Color, modifier: Modifier = Modifier) {
@ReadOnlyComposable
fun getTextColor(config: ActionButtonConfig): Color {
return when {
!config.enabled -> TangemTheme.colors.text.disabled
config.dimContent -> TangemTheme.colors.text.tertiary
!config.isEnabled -> TangemTheme.colors.text.disabled
config.shouldDimContent -> TangemTheme.colors.text.tertiary
else -> TangemTheme.colors.text.primary1
}
}
@ -249,27 +249,27 @@ private class ActionStateProvider : CollectionPreviewParameterProvider<ActionBut
ActionButtonConfig(
text = TextReference.Str(value = "Enabled"),
iconResId = R.drawable.ic_arrow_up_24,
enabled = true,
isEnabled = true,
onClick = {},
showBadge = true,
shouldShowBadge = true,
),
ActionButtonConfig(
text = TextReference.Str(value = "Dimmed"),
iconResId = R.drawable.ic_arrow_up_24,
enabled = true,
dimContent = true,
isEnabled = true,
shouldDimContent = true,
onClick = {},
),
ActionButtonConfig(
text = TextReference.Str(value = "Disabled"),
iconResId = R.drawable.ic_arrow_down_24,
enabled = false,
isEnabled = false,
onClick = {},
),
ActionButtonConfig(
text = TextReference.Str(value = "Loading"),
iconResId = R.drawable.ic_arrow_down_24,
enabled = false,
isEnabled = false,
onClick = {},
isInProgress = true,
),

View file

@ -112,9 +112,9 @@ private fun SegmentedButtonsPreview(
SegmentedButtons(
config = config,
onClick = {},
) {
) { configPreview ->
Text(
text = it.text,
text = configPreview.text,
modifier = Modifier.padding(TangemTheme.dimens.spacing16),
)
}

View file

@ -127,7 +127,7 @@ private fun BoxScope.ContentIconContainer(
)
}
if (icon.showCustomBadge) {
if (icon.shouldShowCustomBadge) {
CurrencyIconBottomBadge(
modifier = Modifier.align(Alignment.BottomEnd),
)

View file

@ -15,7 +15,7 @@ import com.tangem.core.ui.extensions.TextReference
sealed class CurrencyIconState {
abstract val isGrayscale: Boolean
abstract val showCustomBadge: Boolean
abstract val shouldShowCustomBadge: Boolean
abstract val topBadgeIconResId: Int?
/**
@ -24,13 +24,13 @@ sealed class CurrencyIconState {
* @property url The URL where the coin icon can be fetched from. May be `null` if not found.
* @property fallbackResId The drawable resource ID to be used as a fallback if the URL is not available.
* @property isGrayscale Specifies whether to show the icon in grayscale.
* @property showCustomBadge Specifies whether to show the custom token badge.
* @property shouldShowCustomBadge Specifies whether to show the custom token badge.
*/
data class CoinIcon(
val url: String?,
@DrawableRes val fallbackResId: Int,
override val isGrayscale: Boolean,
override val showCustomBadge: Boolean,
override val shouldShowCustomBadge: Boolean,
) : CurrencyIconState() {
override val topBadgeIconResId: Int? = null
@ -42,7 +42,7 @@ sealed class CurrencyIconState {
* @property url The URL where the token icon can be fetched from. May be `null` if not found.
* @property topBadgeIconResId The drawable resource ID for the network badge. May be `null`.
* @property isGrayscale Specifies whether to show the icon in grayscale.
* @property showCustomBadge Specifies whether to show the custom token badge.
* @property shouldShowCustomBadge Specifies whether to show the custom token badge.
* @property fallbackTint The color to be used for tinting the fallback icon.
* @property fallbackBackground The background color to be used for the fallback icon.
*/
@ -50,7 +50,7 @@ sealed class CurrencyIconState {
val url: String?,
@DrawableRes override val topBadgeIconResId: Int?,
override val isGrayscale: Boolean,
override val showCustomBadge: Boolean,
override val shouldShowCustomBadge: Boolean,
val fallbackTint: Color,
val fallbackBackground: Color,
) : CurrencyIconState()
@ -62,14 +62,14 @@ sealed class CurrencyIconState {
* @property background The background color to be used for the icon.
* @property topBadgeIconResId The drawable resource ID for the network badge.
* @property isGrayscale Specifies whether to show the icon in grayscale.
* @property showCustomBadge Specifies whether to show the custom token badge.
* @property shouldShowCustomBadge Specifies whether to show the custom token badge.
*/
data class CustomTokenIcon(
val tint: Color,
val background: Color,
@DrawableRes override val topBadgeIconResId: Int,
override val isGrayscale: Boolean,
override val showCustomBadge: Boolean = true,
override val shouldShowCustomBadge: Boolean = true,
) : CurrencyIconState()
/**
@ -83,13 +83,13 @@ sealed class CurrencyIconState {
@DrawableRes val fallbackResId: Int,
) : CurrencyIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val shouldShowCustomBadge: Boolean = false
override val topBadgeIconResId: Int? = null
}
@Immutable
sealed class CryptoPortfolio : CurrencyIconState() {
override val showCustomBadge: Boolean = false
override val shouldShowCustomBadge: Boolean = false
override val topBadgeIconResId: Int? = null
abstract val color: Color
@ -108,13 +108,13 @@ sealed class CurrencyIconState {
data object Loading : CurrencyIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val shouldShowCustomBadge: Boolean = false
override val topBadgeIconResId: Int? = null
}
data object Locked : CurrencyIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val shouldShowCustomBadge: Boolean = false
override val topBadgeIconResId: Int? = null
}
@ -122,27 +122,27 @@ sealed class CurrencyIconState {
@DrawableRes val resId: Int = R.drawable.ic_empty_64,
) : CurrencyIconState() {
override val isGrayscale: Boolean = true
override val showCustomBadge: Boolean = false
override val shouldShowCustomBadge: Boolean = false
override val topBadgeIconResId: Int? = null
}
fun copySealed(
isGrayscale: Boolean = this.isGrayscale,
showCustomBadge: Boolean = this.showCustomBadge,
showCustomBadge: Boolean = this.shouldShowCustomBadge,
topBadgeIconResId: Int? = this.topBadgeIconResId,
): CurrencyIconState = when (this) {
is CoinIcon -> copy(
isGrayscale = isGrayscale,
showCustomBadge = showCustomBadge,
shouldShowCustomBadge = showCustomBadge,
)
is CustomTokenIcon -> copy(
isGrayscale = isGrayscale,
showCustomBadge = showCustomBadge,
shouldShowCustomBadge = showCustomBadge,
topBadgeIconResId = topBadgeIconResId ?: this.topBadgeIconResId,
)
is TokenIcon -> copy(
isGrayscale = isGrayscale,
showCustomBadge = showCustomBadge,
shouldShowCustomBadge = showCustomBadge,
topBadgeIconResId = topBadgeIconResId,
)
is CryptoPortfolio.Icon -> copy(

View file

@ -28,7 +28,7 @@ object CurrencyIconStateBuilder {
url = url,
fallbackResId = fallbackResId,
isGrayscale = isGrayscale,
showCustomBadge = showCustomBadge,
shouldShowCustomBadge = showCustomBadge,
)
private fun createTokenIcon(
@ -44,7 +44,7 @@ object CurrencyIconStateBuilder {
isGrayscale = isGrayscale,
fallbackTint = fallbackTint,
fallbackBackground = fallbackBackground,
showCustomBadge = showCustomBadge,
shouldShowCustomBadge = showCustomBadge,
)
private fun createCustomTokenIcon(
@ -58,7 +58,7 @@ object CurrencyIconStateBuilder {
background = background,
topBadgeIconResId = topBadgeIconResId,
isGrayscale = isGrayscale,
showCustomBadge = showCustomBadge,
shouldShowCustomBadge = showCustomBadge,
)
private fun fromCoin(
@ -77,8 +77,8 @@ object CurrencyIconStateBuilder {
isGrayscale: Boolean = false,
showCustomBadge: Boolean = true,
): CurrencyIconState {
val grayScale = isGrayscale || token.network.isTestnet
val background = token.tryGetBackgroundForTokenIcon(grayScale)
val isGrayscaleOrTestnet = isGrayscale || token.network.isTestnet
val background = token.tryGetBackgroundForTokenIcon(isGrayscaleOrTestnet)
val tint = getTintForTokenIcon(background)
return if (token.isCustom && token.iconUrl == null) {
@ -86,14 +86,14 @@ object CurrencyIconStateBuilder {
tint = tint,
background = background,
topBadgeIconResId = token.networkIconResId,
isGrayscale = grayScale,
isGrayscale = isGrayscaleOrTestnet,
showCustomBadge = showCustomBadge,
)
} else {
createTokenIcon(
url = token.iconUrl,
topBadgeIconResId = token.networkIconResId,
isGrayscale = grayScale,
isGrayscale = isGrayscaleOrTestnet,
fallbackTint = tint,
fallbackBackground = background,
showCustomBadge = token.isCustom && showCustomBadge,

View file

@ -62,7 +62,7 @@ class CryptoCurrencyToIconStateConverter(
url = coin.iconUrl,
fallbackResId = coin.networkIconResId,
isGrayscale = forceGrayscale || coin.network.isTestnet || isUnreachable || !isAvailable,
showCustomBadge = coin.isCustom && showCustomBadge,
shouldShowCustomBadge = coin.isCustom && showCustomBadge,
)
}
@ -72,8 +72,8 @@ class CryptoCurrencyToIconStateConverter(
showCustomBadge: Boolean = true,
forceGrayscale: Boolean = false,
): CurrencyIconState {
val grayScale = forceGrayscale || token.network.isTestnet || isErrorStatus || !isAvailable
val background = token.tryGetBackgroundForTokenIcon(grayScale)
val isGrayscale = forceGrayscale || token.network.isTestnet || isErrorStatus || !isAvailable
val background = token.tryGetBackgroundForTokenIcon(isGrayscale)
val tint = getTintForTokenIcon(background)
return if (token.isCustom && token.iconUrl == null) {
@ -81,17 +81,17 @@ class CryptoCurrencyToIconStateConverter(
tint = tint,
background = background,
topBadgeIconResId = token.networkIconResId,
isGrayscale = grayScale,
showCustomBadge = showCustomBadge,
isGrayscale = isGrayscale,
shouldShowCustomBadge = showCustomBadge,
)
} else {
CurrencyIconState.TokenIcon(
url = token.iconUrl,
topBadgeIconResId = token.networkIconResId,
isGrayscale = grayScale,
isGrayscale = isGrayscale,
fallbackTint = tint,
fallbackBackground = background,
showCustomBadge = token.isCustom && showCustomBadge, // `true` for tokens with custom derivation
shouldShowCustomBadge = token.isCustom && showCustomBadge, // `true` for tokens with custom derivation
)
}
}

View file

@ -221,9 +221,9 @@ internal data class DropdownMenuPositionProvider(
val toTop = anchorBounds.top - contentOffsetY - popupContentSize.height
val toCenter = anchorBounds.top - popupContentSize.height / 2
val toDisplayBottom = windowSize.height - popupContentSize.height - verticalMargin
val y = sequenceOf(toBottom, toTop, toCenter, toDisplayBottom).firstOrNull {
it >= verticalMargin &&
it + popupContentSize.height <= windowSize.height - verticalMargin
val y = sequenceOf(toBottom, toTop, toCenter, toDisplayBottom).firstOrNull { element ->
element >= verticalMargin &&
element + popupContentSize.height <= windowSize.height - verticalMargin
} ?: toTop
onPositionCalculated(

View file

@ -189,24 +189,24 @@ private class AmountTextFieldPreviewProvider : PreviewParameterProvider<AmountTe
value = "1000000,123123",
decimals = 3,
placeholderAlignment = TopStart,
showPlaceholder = true,
shouldShowPlaceholder = true,
),
AmountTextFieldPreviewData(
value = "1000000.123123",
decimals = 6,
placeholderAlignment = TopStart,
showPlaceholder = false,
shouldShowPlaceholder = false,
),
AmountTextFieldPreviewData(
value = null,
decimals = 2,
showPlaceholder = true,
shouldShowPlaceholder = true,
placeholderAlignment = TopCenter,
),
AmountTextFieldPreviewData(
value = null,
decimals = 2,
showPlaceholder = true,
shouldShowPlaceholder = true,
placeholderAlignment = TopStart,
),
)
@ -215,7 +215,7 @@ private class AmountTextFieldPreviewProvider : PreviewParameterProvider<AmountTe
private data class AmountTextFieldPreviewData(
val value: String? = null,
val decimals: Int = 2,
val showPlaceholder: Boolean,
val shouldShowPlaceholder: Boolean,
val placeholderAlignment: Alignment,
)
// endregion

View file

@ -72,7 +72,12 @@ fun AutoSizeTextField(
) {
BoxWithConstraints(modifier = boxModifier) {
val fontSize = if (isAutoResize) {
resizeFont(visualTransformation, value, textStyle, reduceFactor)
resizeFont(
visualTransformation = visualTransformation,
value = value,
textStyle = textStyle,
reduceFactor = reduceFactor,
)
} else {
textStyle.fontSize
}
@ -141,7 +146,7 @@ private fun AmountTextFieldPreview(
textFieldModifier = Modifier.fillMaxWidth(),
value = text,
onValueChange = { text = it },
centered = data.centered,
centered = data.isCentered,
isAutoResize = data.isAutoResize,
placeholder = data.placeholder,
)
@ -154,43 +159,43 @@ private class AutoSizeTextFieldPreviewProvider : PreviewParameterProvider<AutoSi
value = "AutoSizeTextField",
placeholder = stringReference("placeholder"),
isAutoResize = true,
centered = false,
isCentered = false,
),
AutoSizeTextFieldPreviewData(
value = "AutoSizeTextFieldAutoSizeTextFieldAutoSizeTextFieldAutoSizeTextField",
placeholder = stringReference("placeholder"),
isAutoResize = true,
centered = false,
isCentered = false,
),
AutoSizeTextFieldPreviewData(
value = "AutoSizeTextFieldAutoSizeTextFieldAutoSizeTextFieldAutoSizeTextField",
placeholder = stringReference("Placeholder"),
isAutoResize = true,
centered = false,
isCentered = false,
),
AutoSizeTextFieldPreviewData(
value = "",
placeholder = stringReference("Placeholder"),
isAutoResize = true,
centered = false,
isCentered = false,
),
AutoSizeTextFieldPreviewData(
value = "AutoSizeTextField",
placeholder = stringReference("Placeholder"),
isAutoResize = false,
centered = true,
isCentered = true,
),
AutoSizeTextFieldPreviewData(
value = "AutoSizeTextFieldAutoSizeTextFieldAutoSizeTextFieldAutoSizeTextField",
placeholder = stringReference("Placeholder"),
isAutoResize = false,
centered = true,
isCentered = true,
),
AutoSizeTextFieldPreviewData(
value = "",
placeholder = stringReference("Placeholder"),
isAutoResize = false,
centered = true,
isCentered = true,
),
)
}
@ -199,6 +204,6 @@ private data class AutoSizeTextFieldPreviewData(
val value: String,
val placeholder: TextReference,
val isAutoResize: Boolean,
val centered: Boolean,
val isCentered: Boolean,
)
// endregion

View file

@ -47,9 +47,9 @@ fun PinTextField(
BasicTextField(
value = textFieldValue,
onValueChange = {
if (it.text.length <= length) {
onValueChange(it.text)
onValueChange = { value ->
if (value.text.length <= length) {
onValueChange(value.text)
}
},
modifier = modifier

View file

@ -56,8 +56,8 @@ fun SearchBar(
modifier = modifier
.fillMaxWidth()
.heightIn(min = TangemTheme.dimens.size48)
.onFocusChanged {
if (it.isFocused) {
.onFocusChanged { focusState ->
if (focusState.isFocused) {
state.onActiveChange(true)
} else {
state.onActiveChange(false)

View file

@ -51,10 +51,10 @@ fun SimpleDialogTextField(
val strokeWidth = 2f
val y = size.height - strokeWidth / 2
drawLine(
strokeColor,
Offset(0f, y),
Offset(size.width, y),
strokeWidth,
color = strokeColor,
start = Offset(0f, y),
end = Offset(size.width, y),
strokeWidth = strokeWidth,
)
},
decorationBox = { textValue ->

View file

@ -91,10 +91,10 @@ fun SimpleTextField(
onValueChange = { newTextFieldValueState ->
textFieldValueState = newTextFieldValueState
val stringChangedSinceLastInvocation = lastTextValue != newTextFieldValueState.text
val isStringChangedSinceLastInvocation = lastTextValue != newTextFieldValueState.text
lastTextValue = newTextFieldValueState.text
if (stringChangedSinceLastInvocation) onValueChange(newTextFieldValueState.text)
if (isStringChangedSinceLastInvocation) onValueChange(newTextFieldValueState.text)
},
textStyle = textStyle,
cursorBrush = SolidColor(TangemTheme.colors.text.primary1),
@ -133,9 +133,9 @@ private fun SimpleTextPlaceholder(
AnimatedContent(
targetState = placeholder,
label = "Placeholder Change Animation",
) {
) { placeholder ->
Text(
text = it.resolveReference(),
text = placeholder.resolveReference(),
style = textStyle,
color = color,
)

View file

@ -93,10 +93,10 @@ private inline fun <T> VerticalGrid(
private fun Preview() {
TangemThemePreview {
EnumeratedTwoColumnGrid(
items = List(24) {
items = List(24) { i ->
EnumeratedTwoColumnGridItem(
index = it + 1,
mnemonic = "word${it + 1}",
index = i + 1,
mnemonic = "word${i + 1}",
)
}.toImmutableList(),
)

View file

@ -81,7 +81,7 @@ fun InputRowBestRate(
)
}
SpacerWMax()
onIconClick?.let {
if (onIconClick != null) {
Icon(
painter = painterResource(id = R.drawable.ic_chevron_right_24),
contentDescription = null,
@ -144,7 +144,7 @@ private fun InputRowBestRatePreview(
title = data.title,
titleExtra = data.titleExtra,
subtitle = data.subtitle,
showTag = data.showTag,
showTag = data.shouldShowTag,
onIconClick = data.iconClick,
modifier = Modifier
.background(TangemTheme.colors.background.action),
@ -155,7 +155,7 @@ private fun InputRowBestRatePreview(
private data class InputRowBestRatePreviewData(
val title: TextReference,
val titleExtra: TextReference,
val showTag: Boolean,
val shouldShowTag: Boolean,
val subtitle: TextReference,
val iconClick: (() -> Unit)?,
)
@ -167,14 +167,14 @@ private class InputRowBestRatePreviewDataProvider : PreviewParameterProvider<Inp
title = TextReference.Str("1inch"),
titleExtra = TextReference.Str("DEX"),
subtitle = TextReference.Str("0,64554846 DAI ≈ 1 MATIC "),
showTag = true,
shouldShowTag = true,
iconClick = {},
),
InputRowBestRatePreviewData(
title = TextReference.Str("ChangeNow"),
titleExtra = TextReference.Str("CEX"),
subtitle = TextReference.Str("0,64554846 DAI ≈ 1 MATIC "),
showTag = false,
shouldShowTag = false,
iconClick = null,
),
)

View file

@ -69,7 +69,7 @@ fun InputRowDefault(
.weight(1f)
.testTag(BaseBlockTestTags.BLOCK),
) {
title?.let {
title?.let { title ->
Text(
text = title.resolveReference(),
style = TangemTheme.typography.subtitle2,
@ -86,7 +86,7 @@ fun InputRowDefault(
modifier = Modifier.testTag(BaseBlockTestTags.BLOCK_TEXT),
)
}
iconRes?.let {
iconRes?.let { iconRes ->
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
@ -120,7 +120,7 @@ private fun InputRowDefaultPreview(
title = TextReference.Str(data.title),
text = TextReference.Str(data.text),
iconRes = data.iconRes,
showDivider = data.showDivider,
showDivider = data.shouldShowDivider,
modifier = Modifier.background(TangemTheme.colors.background.action),
)
}
@ -130,7 +130,7 @@ private data class InputRowDefaultPreviewData(
val title: String,
val text: String,
val iconRes: Int?,
val showDivider: Boolean,
val shouldShowDivider: Boolean,
)
private class InputRowDefaultPreviewDataProvider : PreviewParameterProvider<InputRowDefaultPreviewData> {
@ -140,13 +140,13 @@ private class InputRowDefaultPreviewDataProvider : PreviewParameterProvider<Inpu
title = "title",
text = "text",
iconRes = null,
showDivider = true,
shouldShowDivider = true,
),
InputRowDefaultPreviewData(
title = "title",
text = "text",
iconRes = R.drawable.ic_chevron_right_24,
showDivider = false,
shouldShowDivider = false,
),
)
}

View file

@ -116,7 +116,7 @@ fun InputRowEnter(
.padding(top = TangemTheme.dimens.spacing8),
)
}
iconRes?.let {
iconRes?.let { iconRes ->
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
@ -148,7 +148,7 @@ private fun InputRowEnterPreview(
title = TextReference.Str(data.title),
text = data.text,
iconRes = data.iconRes,
showDivider = data.showDivider,
showDivider = data.shouldShowDivider,
description = stringReference(""),
onValueChange = {},
modifier = Modifier.background(TangemTheme.colors.background.action),
@ -160,7 +160,7 @@ private data class InputRowEnterPreviewData(
val title: String,
val text: String,
val iconRes: Int?,
val showDivider: Boolean,
val shouldShowDivider: Boolean,
)
private class InputRowEnterPreviewDataProvider :
@ -171,13 +171,13 @@ private class InputRowEnterPreviewDataProvider :
title = "title",
text = "text",
iconRes = null,
showDivider = true,
shouldShowDivider = true,
),
InputRowEnterPreviewData(
title = "title",
text = "text",
iconRes = R.drawable.ic_chevron_right_24,
showDivider = false,
shouldShowDivider = false,
),
)
}

View file

@ -93,7 +93,7 @@ fun InputRowEnterAmount(
.padding(top = TangemTheme.dimens.spacing8),
)
}
iconRes?.let {
iconRes?.let { iconRes ->
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,

View file

@ -77,9 +77,9 @@ fun InputRowEnterInfo(
.padding(top = TangemTheme.dimens.spacing8)
.weight(1f),
)
info?.let {
info?.let { info ->
Text(
text = it.resolveReference(),
text = info.resolveReference(),
style = TangemTheme.typography.body2,
color = infoColor,
modifier = Modifier
@ -104,7 +104,7 @@ private fun InputRowEnterInfoPreview(
title = data.title,
text = data.text,
info = data.info,
showDivider = data.showDivider,
showDivider = data.shouldShowDivider,
onValueChange = {},
modifier = Modifier.background(TangemTheme.colors.background.action),
)
@ -114,7 +114,7 @@ private fun InputRowEnterInfoPreview(
private data class InputRowEnterInfoPreviewData(
val title: TextReference,
val text: String,
val showDivider: Boolean,
val shouldShowDivider: Boolean,
val info: TextReference?,
)
@ -125,13 +125,13 @@ private class InputRowEnterInfoPreviewDataProvider :
InputRowEnterInfoPreviewData(
title = TextReference.Str("title"),
text = "text",
showDivider = true,
shouldShowDivider = true,
info = TextReference.Str("info"),
),
InputRowEnterInfoPreviewData(
title = TextReference.Str("title"),
text = "text",
showDivider = false,
shouldShowDivider = false,
info = null,
),
)

View file

@ -97,9 +97,9 @@ fun InputRowEnterInfoAmount(
.padding(top = TangemTheme.dimens.spacing8)
.weight(1f),
)
info?.let {
info?.let { info ->
Text(
text = it.resolveReference(),
text = info.resolveReference(),
style = TangemTheme.typography.body2,
color = infoColor,
modifier = Modifier
@ -185,9 +185,9 @@ fun InputRowEnterInfoAmountV2(
.padding(top = TangemTheme.dimens.spacing8)
.weight(1f),
)
info?.let {
info?.let { info ->
Text(
text = it.resolveReference(),
text = info.resolveReference(),
style = TangemTheme.typography.body2,
color = infoColor,
modifier = Modifier

View file

@ -102,7 +102,7 @@ fun InputRowImage(
modifier = Modifier.padding(top = TangemTheme.dimens.spacing2),
)
}
iconRes?.let {
iconRes?.let { iconRes ->
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
@ -137,7 +137,7 @@ private fun InputRowInputEnterInfoPreview(
iconRes = data.actionIconRes,
onIconClick = {},
showNetworkIcon = false,
showDivider = data.showDivider,
showDivider = data.shouldShowDivider,
)
}
}
@ -147,9 +147,9 @@ private data class InputRowImagePreviewData(
val subtitle: TextReference,
val caption: TextReference,
val iconState: CurrencyIconState,
val showDivider: Boolean,
val shouldShowDivider: Boolean,
val actionIconRes: Int?,
val showNetworkIcon: Boolean = false,
val shouldShowNetworkIcon: Boolean = false,
)
private class InputRowImagePreviewDataProvider :
@ -162,8 +162,8 @@ private class InputRowImagePreviewDataProvider :
caption = TextReference.Str("caption"),
iconState = CurrencyIconState.Locked,
actionIconRes = null,
showDivider = false,
showNetworkIcon = false,
shouldShowDivider = false,
shouldShowNetworkIcon = false,
),
InputRowImagePreviewData(
title = TextReference.Str("title"),
@ -171,8 +171,8 @@ private class InputRowImagePreviewDataProvider :
caption = TextReference.Str("caption"),
iconState = CurrencyIconState.Locked,
actionIconRes = R.drawable.ic_chevron_right_24,
showDivider = true,
showNetworkIcon = true,
shouldShowDivider = true,
shouldShowNetworkIcon = true,
),
)
}

View file

@ -115,7 +115,7 @@ fun InputRowImageInfo(
color = TangemTheme.colors.text.primary1,
)
}
infoSubtitle?.let {
if (infoSubtitle != null) {
if (infoSubtitle is TextReference.Annotated) {
Text(
text = infoSubtitle.resolveAnnotatedReference(),

View file

@ -118,7 +118,7 @@ private fun InputRowImageSelectorPreview(
private data class InputRowImageSelectorPreviewData(
val subtitle: TextReference,
val caption: TextReference,
val showDivider: Boolean,
val shouldShowDivider: Boolean,
val actionIconRes: Int?,
val isSelected: Boolean,
)
@ -131,14 +131,14 @@ private class InputRowImageSelectorPreviewDataProvider :
subtitle = TextReference.Str("subtitle"),
caption = TextReference.Str("caption"),
actionIconRes = null,
showDivider = false,
shouldShowDivider = false,
isSelected = false,
),
InputRowImageSelectorPreviewData(
subtitle = TextReference.Str("subtitle"),
caption = TextReference.Str("caption"),
actionIconRes = R.drawable.ic_chevron_right_24,
showDivider = true,
shouldShowDivider = true,
isSelected = true,
),
)

View file

@ -89,9 +89,9 @@ fun InputRowRecipient(
.fillMaxWidth()
.padding(TangemTheme.dimens.spacing12),
) {
AnimatedContent(targetState = titleText, label = "Title Change") {
AnimatedContent(targetState = titleText, label = "Title Change") { title ->
Text(
text = it.resolveReference(),
text = title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = color,
modifier = Modifier.testTag(SendAddressScreenTestTags.ADDRESS_TEXT_FIELD_TITLE),

View file

@ -10,7 +10,7 @@ fun InfiniteListHandler(
buffer: Int = 2,
triggerLoadMoreCheckOnItemsCountChange: Boolean = false,
) {
val loadMore by remember(buffer, listState) {
val shouldLoadMore by remember(buffer, listState) {
derivedStateOf {
val layoutInfo = listState.layoutInfo
val totalItemsNumber = layoutInfo.totalItemsCount
@ -21,17 +21,17 @@ fun InfiniteListHandler(
}
val totalItemsCount by remember(listState) { derivedStateOf { listState.layoutInfo.totalItemsCount } }
var emitted by remember(totalItemsCount, buffer, listState) { mutableStateOf(false) }
var isEmitted by remember(key1 = totalItemsCount, key2 = buffer, key3 = listState) { mutableStateOf(false) }
LaunchedEffect(loadMore) {
if (loadMore && !emitted) {
emitted = onLoadMore()
LaunchedEffect(shouldLoadMore) {
if (shouldLoadMore && !isEmitted) {
isEmitted = onLoadMore()
}
}
LaunchedEffect(totalItemsCount) {
if (triggerLoadMoreCheckOnItemsCountChange && loadMore && !emitted) {
emitted = onLoadMore()
if (triggerLoadMoreCheckOnItemsCountChange && shouldLoadMore && !isEmitted) {
isEmitted = onLoadMore()
}
}
}

View file

@ -111,9 +111,21 @@ private fun Preview_Notification() {
url = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/usd-coin.png",
topBadgeIconResId = R.drawable.ic_polygon_22,
isGrayscale = false,
showCustomBadge = false,
fallbackTint = Color(1.0f, 1.0f, 1.0f, 1.0f, ColorSpaces.Srgb),
fallbackBackground = Color(0.23529412f, 0.28627452f, 0.6117647f, 1.0f, ColorSpaces.Srgb),
shouldShowCustomBadge = false,
fallbackTint = Color(
red = 1.0f,
green = 1.0f,
blue = 1.0f,
alpha = 1.0f,
colorSpace = ColorSpaces.Srgb,
),
fallbackBackground = Color(
red = 0.23529412f,
green = 0.28627452f,
blue = 0.6117647f,
alpha = 1.0f,
colorSpace = ColorSpaces.Srgb,
),
),
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = stringReference("Go to token"),

View file

@ -52,9 +52,9 @@ fun NoteMigrationNotification(config: NotificationConfig, modifier: Modifier = M
verticalArrangement = Arrangement.spacedBy(10.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
config.title?.let {
config.title?.let { title ->
Text(
text = it.resolveReference(),
text = title.resolveReference(),
color = TangemColorPalette.White,
style = TangemTheme.typography.h3,
)

View file

@ -84,7 +84,7 @@ fun Notification(
titleColor = titleColor,
subtitle = config.subtitle,
subtitleColor = subtitleColor,
showArrowIcon = isEnabled && config.showArrowIcon,
showArrowIcon = isEnabled && config.shouldShowArrowIcon,
)
}
}
@ -256,7 +256,7 @@ private fun SingleSecondaryButton(config: NotificationButtonsState.SecondaryButt
modifier = Modifier.fillMaxWidth(),
iconResId = config.iconResId,
enabled = isEnabled,
showProgress = config.showProgress,
showProgress = config.shouldShowProgress,
)
} else {
SecondaryButton(
@ -265,7 +265,7 @@ private fun SingleSecondaryButton(config: NotificationButtonsState.SecondaryButt
modifier = Modifier.fillMaxWidth(),
size = TangemButtonSize.WideAction,
enabled = isEnabled,
showProgress = config.showProgress,
showProgress = config.shouldShowProgress,
)
}
}

View file

@ -26,7 +26,7 @@ data class NotificationConfig(
val buttonsState: ButtonsState? = null,
val onClick: (() -> Unit)? = null,
val onCloseClick: (() -> Unit)? = null,
val showArrowIcon: Boolean = onClick != null,
val shouldShowArrowIcon: Boolean = onClick != null,
val iconTint: IconTint = IconTint.Unspecified,
val iconSize: Dp = 20.dp,
) {
@ -44,7 +44,7 @@ data class NotificationConfig(
val text: TextReference,
@DrawableRes val iconResId: Int? = null,
val onClick: () -> Unit,
val showProgress: Boolean = false,
val shouldShowProgress: Boolean = false,
) : ButtonsState()
data class PairButtonsConfig(

View file

@ -57,7 +57,13 @@ fun TangemLinearProgressIndicator(
) {
val strokeWidth = size.height
drawLinearIndicatorBackground(backgroundColor, strokeWidth, strokeCap)
drawLinearIndicator(0f, coercedProgress(), color, strokeWidth, strokeCap)
drawLinearIndicator(
startFraction = 0f,
endFraction = coercedProgress(),
color = color,
strokeWidth = strokeWidth,
strokeCap = strokeCap,
)
}
}
@ -144,11 +150,11 @@ fun TangemLinearProgressIndicator(
}
if ((secondLineHead - secondLineTail) > 0) {
drawLinearIndicator(
secondLineHead,
secondLineTail,
color,
strokeWidth,
strokeCap,
startFraction = secondLineHead,
endFraction = secondLineTail,
color = color,
strokeWidth = strokeWidth,
strokeCap = strokeCap,
)
}
}
@ -209,18 +215,24 @@ private fun DrawScope.drawLinearIndicator(
if (abs(endFraction - startFraction) > 0) {
// Progress line
drawLine(
color,
Offset(adjustedBarStart, yOffset),
Offset(adjustedBarEnd, yOffset),
strokeWidth,
strokeCap,
color = color,
start = Offset(adjustedBarStart, yOffset),
end = Offset(adjustedBarEnd, yOffset),
strokeWidth = strokeWidth,
cap = strokeCap,
)
}
}
}
private fun DrawScope.drawLinearIndicatorBackground(color: Color, strokeWidth: Float, strokeCap: StrokeCap) =
drawLinearIndicator(0f, 1f, color, strokeWidth, strokeCap)
drawLinearIndicator(
startFraction = 0f,
endFraction = 1f,
color = color,
strokeWidth = strokeWidth,
strokeCap = strokeCap,
)
// Indeterminate linear indicator transition specs
// Total duration for one cycle
@ -238,10 +250,10 @@ private const val FIRST_LINE_TAIL_DELAY = 333
private const val SECOND_LINE_HEAD_DELAY = 1000
private const val SECOND_LINE_TAIL_DELAY = 1267
private val FIRST_LINE_HEAD_EASING = CubicBezierEasing(0.2f, 0f, 0.8f, 1f)
private val FIRST_LINE_TAIL_EASING = CubicBezierEasing(0.4f, 0f, 1f, 1f)
private val SECOND_LINE_HEAD_EASING = CubicBezierEasing(0f, 0f, 0.65f, 1f)
private val SECOND_LINE_TAIL_EASING = CubicBezierEasing(0.1f, 0f, 0.45f, 1f)
private val FIRST_LINE_HEAD_EASING = CubicBezierEasing(a = 0.2f, b = 0f, c = 0.8f, d = 1f)
private val FIRST_LINE_TAIL_EASING = CubicBezierEasing(a = 0.4f, b = 0f, c = 1f, d = 1f)
private val SECOND_LINE_HEAD_EASING = CubicBezierEasing(a = 0f, b = 0f, c = 0.65f, d = 1f)
private val SECOND_LINE_TAIL_EASING = CubicBezierEasing(a = 0.1f, 0f, 0.45f, d = 1f)
// region Preview
@Preview(showBackground = true, widthDp = 360)

View file

@ -34,16 +34,16 @@ fun SimpleActionRow(title: String, description: String, modifier: Modifier = Mod
.align(Alignment.CenterStart),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
AnimatedContent(targetState = title, label = "") {
AnimatedContent(targetState = title, label = "") { title ->
Text(
text = it,
text = title,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
)
}
AnimatedContent(targetState = description, label = "") {
AnimatedContent(targetState = description, label = "") { description ->
Text(
text = it,
text = description,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)

View file

@ -37,12 +37,12 @@ fun ChainRow(model: ChainRowUM, modifier: Modifier = Modifier, action: @Composab
RowText(
mainText = model.name,
secondText = model.type,
subtitle = if (model.showCustom) {
subtitle = if (model.shouldShowCustom) {
resourceReference(R.string.common_custom)
} else {
null
},
isEnabled = model.enabled,
isEnabled = model.isEnabled,
accentMainText = true,
accentSecondText = false,
)
@ -95,25 +95,25 @@ private class ChainRowParameterProvider : CollectionPreviewParameterProvider<Cha
name = "Cardano",
type = "ADA",
icon = CurrencyIconState.Locked,
showCustom = true,
shouldShowCustom = true,
),
ChainRowUM(
name = "Binance",
type = "BNB",
icon = CurrencyIconState.Locked,
showCustom = false,
shouldShowCustom = false,
),
ChainRowUM(
name = "123456789010111213141516",
type = "BNB",
icon = CurrencyIconState.Locked,
showCustom = true,
shouldShowCustom = true,
),
ChainRowUM(
name = "123456789010111213141516",
type = "123456789010111213141516",
icon = CurrencyIconState.Locked,
showCustom = false,
shouldShowCustom = false,
),
),
)

View file

@ -8,6 +8,6 @@ data class ChainRowUM(
val name: String,
val type: String,
val icon: CurrencyIconState,
val showCustom: Boolean,
val enabled: Boolean = true,
val shouldShowCustom: Boolean,
val isEnabled: Boolean = true,
)

View file

@ -98,9 +98,9 @@ fun ShowcaseButtons(
bottom = TangemTheme.dimens.spacing16,
),
)
hint?.let {
if (hint != null) {
Text(
text = it.resolveReference(),
text = hint.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier

View file

@ -79,6 +79,6 @@ private fun MessageText(text: String) {
@Composable
private fun Preview_TangemSnackbar(@PreviewParameter(TangemSnackbarModelProvider::class) model: TangemSnackbarModel) {
TangemThemePreview {
TangemSnackbar(data = model.snackbarData, actionOnNewLine = model.actionOnNewLine)
TangemSnackbar(data = model.snackbarData, actionOnNewLine = model.hasActionOnNewLine)
}
}

View file

@ -46,7 +46,7 @@ private fun Preview_TangemSnackbar(@PreviewParameter(TangemSnackbarModelProvider
TangemThemePreview {
val snackbarHostState = remember(::SnackbarHostState)
TangemSnackbarHost(hostState = snackbarHostState, actionOnNewLine = model.actionOnNewLine)
TangemSnackbarHost(hostState = snackbarHostState, actionOnNewLine = model.hasActionOnNewLine)
LaunchedEffect(key1 = null) {
snackbarHostState.showSnackbar(visuals = model.snackbarData.visuals)

View file

@ -5,7 +5,7 @@ import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarVisuals
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
internal data class TangemSnackbarModel(val snackbarData: SnackbarData, val actionOnNewLine: Boolean)
internal data class TangemSnackbarModel(val snackbarData: SnackbarData, val hasActionOnNewLine: Boolean)
internal class TangemSnackbarModelProvider : CollectionPreviewParameterProvider<TangemSnackbarModel>(
listOf(
@ -51,7 +51,7 @@ internal class TangemSnackbarModelProvider : CollectionPreviewParameterProvider<
): TangemSnackbarModel {
return TangemSnackbarModel(
snackbarData = createSnackbarData(message, actionLabel),
actionOnNewLine = actionOnNewLine,
hasActionOnNewLine = actionOnNewLine,
)
}

View file

@ -10,7 +10,7 @@ class StoriesStepStateMachine<T>(
private val isRepeatable: Boolean,
) {
private var _currentIndex = mutableIntStateOf(FIRST_INDEX)
private val _currentIndex = mutableIntStateOf(FIRST_INDEX)
val steps = stories.lastIndex
val currentIndex: IntState

View file

@ -481,7 +481,7 @@ private fun Preview_TokenItem_InLight(@PreviewParameter(TokenItemStateProvider::
private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenItemState>(
collection = listOf(
tokenItemVisibleState.copy(
iconState = coinIconState.copy(showCustomBadge = true),
iconState = coinIconState.copy(shouldShowCustomBadge = true),
titleState = TokenItemState.TitleState.Content(
text = stringReference(value = "PolygonPolygonPolygonPolygonPolygonPolygon"),
hasPending = true,
@ -621,7 +621,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
url = null,
fallbackResId = R.drawable.img_polygon_22,
isGrayscale = false,
showCustomBadge = false,
shouldShowCustomBadge = false,
)
val tokenIconState
@ -631,7 +631,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
fallbackTint = TangemColorPalette.Black,
fallbackBackground = TangemColorPalette.Meadow,
isGrayscale = false,
showCustomBadge = false,
shouldShowCustomBadge = false,
)
private val customTokenIconState

View file

@ -27,13 +27,13 @@ sealed class EmptyTransactionsBlockState(
text = TextReference.Res(R.string.common_reload),
iconResId = R.drawable.ic_refresh_24,
onClick = onReload,
enabled = true,
isEnabled = true,
),
secondButtonConfig = ActionButtonConfig(
text = TextReference.Res(R.string.common_explore),
iconResId = R.drawable.ic_arrow_top_right_24,
onClick = onExplore,
enabled = true,
isEnabled = true,
),
),
iconRes = R.drawable.ic_alert_history_64,
@ -46,7 +46,7 @@ sealed class EmptyTransactionsBlockState(
text = TextReference.Res(R.string.common_explore),
iconResId = R.drawable.ic_arrow_top_right_24,
onClick = onExplore,
enabled = true,
isEnabled = true,
),
),
iconRes = R.drawable.ic_empty_token_64,
@ -59,7 +59,7 @@ sealed class EmptyTransactionsBlockState(
text = TextReference.Res(R.string.common_explore_transaction_history),
iconResId = R.drawable.ic_arrow_top_right_24,
onClick = onExplore,
enabled = true,
isEnabled = true,
),
),
iconRes = R.drawable.ic_compass_64,

View file

@ -27,15 +27,15 @@ sealed interface TextReference {
/**
* Text resource id
*
* @property id resource id
* @property formatArgs arguments. Impossible to use [kotlinx.collections.immutable.ImmutableList] because
* [Any] is unstable.
* @property decapitalize whether resolved reference should be decapitalized
* @property id resource id
* @property formatArgs arguments. Impossible to use [kotlinx.collections.immutable.ImmutableList] because
* [Any] is unstable.
* @property shouldDecapitalize whether resolved reference should be decapitalized
*/
data class Res(
@StringRes val id: Int,
val formatArgs: WrappedList<Any> = WrappedList(emptyList()),
val decapitalize: Boolean = false,
val shouldDecapitalize: Boolean = false,
) : TextReference
/**
@ -171,7 +171,7 @@ fun TextReference.resolveReference(): String {
val resolvedReference = stringResourceSafe(id = id, *args)
if (decapitalize) {
if (shouldDecapitalize) {
resolvedReference.replaceFirstChar { char -> char.lowercase() }
} else {
resolvedReference

View file

@ -17,7 +17,7 @@ open class BigDecimalCryptoFormat(
val symbol: String,
val decimals: Int,
val locale: Locale = Locale.getDefault(),
val ignoreSymbolPosition: Boolean = false,
val shouldIgnoreSymbolPosition: Boolean = false,
) : BigDecimalFormat {
override fun invoke(value: BigDecimal): String = defaultAmount()(value)
@ -56,7 +56,7 @@ fun BigDecimalFormatScope.crypto(
return BigDecimalCryptoFormat(
symbol = cryptoCurrency.symbol,
decimals = cryptoCurrency.decimals,
ignoreSymbolPosition = ignoreSymbolPosition,
shouldIgnoreSymbolPosition = ignoreSymbolPosition,
locale = locale,
)
}
@ -64,7 +64,7 @@ fun BigDecimalFormatScope.crypto(
// == Formatters ==
fun BigDecimalCryptoFormat.defaultAmount() = BigDecimalFormat { value ->
if (ignoreSymbolPosition) {
if (shouldIgnoreSymbolPosition) {
val formatter = NumberFormat.getInstance(locale).apply {
maximumFractionDigits = decimals.coerceAtMost(maximumValue = 8)
minimumFractionDigits = 2

View file

@ -6,7 +6,7 @@ import java.text.NumberFormat
import java.util.Locale
class BigDecimalPercentFormat(
val withoutSign: Boolean = true,
val isWithoutSign: Boolean = true,
val locale: Locale = Locale.getDefault(),
) : BigDecimalFormat {
override fun invoke(value: BigDecimal): String = default()(value)
@ -19,7 +19,7 @@ fun BigDecimalFormatScope.percent(
locale: Locale = Locale.getDefault(),
): BigDecimalPercentFormat {
return BigDecimalPercentFormat(
withoutSign = withoutSign,
isWithoutSign = withoutSign,
locale = locale,
)
}
@ -33,7 +33,7 @@ private fun BigDecimalPercentFormat.default(): BigDecimalFormat = BigDecimalForm
roundingMode = RoundingMode.HALF_UP
}
val valueToFormat = if (withoutSign) value.abs() else value
val valueToFormat = if (isWithoutSign) value.abs() else value
formatter.format(valueToFormat)
}

View file

@ -9,7 +9,6 @@ import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetV2Ds
import com.tangem.core.ui.components.bottomsheets.message.messageBottomSheetUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.SnackbarMessage.Duration
/**
* Event that is used to show a message in the UI.
@ -88,7 +87,7 @@ data class SnackbarMessage(
* @param secondAction The second dialog action to perform. Optional, `null` by default.
* Performing the second action always dismisses the dialog.
* @param isDismissable If `false` then dialog can not be dismissed by back button click or by outside click.
* @param dismissOnFirstAction If `true` then dialog is dismissed when first action is performed,
* @param shouldDismissOnFirstAction If `true` then dialog is dismissed when first action is performed,
* ignoring lambda passed to [EventMessageAction.onClick].
* `true` by default.
* @param onDismissRequest The action to perform when the dialog is dismissed.
@ -99,7 +98,7 @@ data class DialogMessage(
val firstAction: EventMessageAction,
val secondAction: EventMessageAction? = null,
val isDismissable: Boolean = true,
val dismissOnFirstAction: Boolean = true,
val shouldDismissOnFirstAction: Boolean = true,
val onDismissRequest: () -> Unit = {},
) : EventMessage {
@ -138,7 +137,7 @@ data class DialogMessage(
message = message,
title = title,
isDismissable = isDismissable,
dismissOnFirstAction = dismissOnFirstAction,
shouldDismissOnFirstAction = dismissOnFirstAction,
onDismissRequest = onDismissRequest,
firstAction = firstActionBuilder(buttonsScope),
secondAction = secondActionBuilder?.invoke(buttonsScope),
@ -214,14 +213,14 @@ fun bottomSheetMessage(init: @MessageBottomSheetV2Dsl MessageBottomSheetUMV2.()
* Represents an action button in the dialog.
*
* @param title The title of the action.
* @param warning If `true` then the action is highlighted as a warning.
* @param enabled If `false` then the action is disabled.
* @param isWarning If `true` then the action is highlighted as a warning.
* @param isEnabled If `false` then the action is disabled.
* @param onClick The action to perform when the button is clicked.
* */
data class EventMessageAction(
val title: TextReference,
val warning: Boolean = false,
val enabled: Boolean = true,
val isWarning: Boolean = false,
val isEnabled: Boolean = true,
val onClick: () -> Unit,
) {

View file

@ -100,7 +100,7 @@ fun EventMessageEffect(
)
}
loadingMessage?.let {
if (loadingMessage != null) {
LoadingDialog()
}
}
@ -140,7 +140,7 @@ private fun MessageBottomSheet(message: BottomSheetMessage, onDismissRequest: ()
primaryAction = message.firstAction?.let { action ->
MessageBottomSheetUM.ActionUM(
text = action.title,
enabled = action.enabled,
isEnabled = action.isEnabled,
onClick = {
action.onClick()
onDismissRequest()
@ -150,7 +150,7 @@ private fun MessageBottomSheet(message: BottomSheetMessage, onDismissRequest: ()
secondaryAction = message.secondAction?.let { action ->
MessageBottomSheetUM.ActionUM(
text = action.title,
enabled = action.enabled,
isEnabled = action.isEnabled,
onClick = {
action.onClick()
onDismissRequest()
@ -172,12 +172,12 @@ private fun MessageDialog(message: DialogMessage, onDismissRequest: () -> Unit)
confirmButton = message.firstAction.let { action ->
DialogButtonUM(
title = action.title.resolveReference(),
warning = action.warning,
enabled = action.enabled,
isWarning = action.isWarning,
isEnabled = action.isEnabled,
onClick = {
action.onClick()
if (message.dismissOnFirstAction) {
if (message.shouldDismissOnFirstAction) {
onDismissRequest()
}
},
@ -186,8 +186,8 @@ private fun MessageDialog(message: DialogMessage, onDismissRequest: () -> Unit)
dismissButton = message.secondAction?.let { action ->
DialogButtonUM(
title = action.title.resolveReference(),
warning = action.warning,
enabled = action.enabled,
isWarning = action.isWarning,
isEnabled = action.isEnabled,
onClick = {
action.onClick()
onDismissRequest()

View file

@ -49,7 +49,7 @@ object Dialogs {
title = resourceReference(R.string.common_ok),
onClick = {},
),
dismissOnFirstAction = true,
shouldDismissOnFirstAction = true,
onDismissRequest = onDismiss,
)
}

View file

@ -25,7 +25,15 @@ inline fun LazyItemScope.ReorderableItem(
index: Int? = null,
orientationLocked: Boolean = true,
content: @Composable BoxScope.(isDragging: Boolean) -> Unit,
) = ReorderableItem(reorderableState, key, modifier, Modifier.animateItem(), orientationLocked, index, content)
) = ReorderableItem(
state = reorderableState,
key = key,
modifier = modifier,
defaultDraggingModifier = Modifier.animateItem(),
orientationLocked = orientationLocked,
index = index,
content = content,
)
/**
* Fixed version of ReorderableItem from reorderable library.
@ -41,7 +49,15 @@ inline fun LazyGridItemScope.ReorderableItem(
modifier: Modifier = Modifier,
index: Int? = null,
content: @Composable BoxScope.(isDragging: Boolean) -> Unit,
) = ReorderableItem(reorderableState, key, modifier, Modifier.animateItem(), false, index, content)
) = ReorderableItem(
state = reorderableState,
key = key,
modifier = modifier,
defaultDraggingModifier = Modifier.animateItem(),
orientationLocked = false,
index = index,
content = content,
)
/**
* Fixed version of ReorderableItem from reorderable library.
@ -79,7 +95,8 @@ inline fun ReorderableItem(
key == state.dragCancelledAnimation.position?.key
}
if (cancel) {
Modifier.zIndex(1f)
Modifier
.zIndex(1f)
.graphicsLayer {
translationX = if (!orientationLocked || !state.isVerticalScroll) {
state.dragCancelledAnimation.offset.x

View file

@ -162,15 +162,15 @@ fun String.parseBigDecimalOrNull() = runCatching {
// We assume there will be only decimal separator, otherwise parsing will fail.
// Step 1. Exclude formatted (100,000.0) except scientific notation (100.000e10)
val excludeFormatted = this.count {
val shouldExcludeFormatted = this.count {
!it.isDigit() && !it.equals(SCIENTIFIC_NOTATION, ignoreCase = true)
} > DECIMAL_SEPARATOR_LIMIT
// Step 2. Exclude wrong scientific notation (100e100e100)
val excludeWrongScientific = this.count {
val shouldExcludeWrongScientific = this.count {
it.equals(SCIENTIFIC_NOTATION, ignoreCase = true)
} > DECIMAL_SEPARATOR_LIMIT
if (excludeFormatted || excludeWrongScientific) return null
if (shouldExcludeFormatted || shouldExcludeWrongScientific) return null
// An attempt to parse value with POINT decimal separator
val parsed = this.toBigDecimalOrNull()

View file

@ -7,4 +7,9 @@ fun Path.lineTo(offset: Offset) = lineTo(offset.x, offset.y)
fun Path.moveTo(offset: Offset) = moveTo(offset.x, offset.y)
fun Path.quadraticBezierTo(control: Offset, end: Offset) = quadraticBezierTo(control.x, control.y, end.x, end.y)
fun Path.quadraticBezierTo(control: Offset, end: Offset) = quadraticBezierTo(
x1 = control.x,
y1 = control.y,
x2 = end.x,
y2 = end.y,
)

View file

@ -30,7 +30,7 @@ fun PreviewShimmerContainer(actualContent: @Composable () -> Unit, shimmerConten
}
SpacerH4()
var shimmerVisible by remember { mutableStateOf(true) }
var isShimmerVisible by remember { mutableStateOf(true) }
TangemThemePreview {
Box(
@ -39,7 +39,7 @@ fun PreviewShimmerContainer(actualContent: @Composable () -> Unit, shimmerConten
},
) {
actualContent()
if (shimmerVisible) {
if (isShimmerVisible) {
shimmerContent()
}
}
@ -48,7 +48,7 @@ fun PreviewShimmerContainer(actualContent: @Composable () -> Unit, shimmerConten
LaunchedEffect(Unit) {
while (true) {
delay(timeMillis = 2000)
shimmerVisible = !shimmerVisible
isShimmerVisible = !isShimmerVisible
}
}
}