Updated on 2026-08-14
This commit is contained in:
parent
acf110dbcc
commit
6910f74fd9
242 changed files with 866 additions and 732 deletions
|
|
@ -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 = {},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ data class MessageBottomSheetUM(
|
|||
|
||||
data class ActionUM(
|
||||
val text: TextReference,
|
||||
val enabled: Boolean = true,
|
||||
val isEnabled: Boolean = true,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
},
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ private fun BoxScope.ContentIconContainer(
|
|||
)
|
||||
}
|
||||
|
||||
if (icon.showCustomBadge) {
|
||||
if (icon.shouldShowCustomBadge) {
|
||||
CurrencyIconBottomBadge(
|
||||
modifier = Modifier.align(Alignment.BottomEnd),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ fun InputRowEnterAmount(
|
|||
.padding(top = TangemTheme.dimens.spacing8),
|
||||
)
|
||||
}
|
||||
iconRes?.let {
|
||||
iconRes?.let { iconRes ->
|
||||
Icon(
|
||||
painter = painterResource(id = iconRes),
|
||||
contentDescription = null,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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,
|
||||
) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ object Dialogs {
|
|||
title = resourceReference(R.string.common_ok),
|
||||
onClick = {},
|
||||
),
|
||||
dismissOnFirstAction = true,
|
||||
shouldDismissOnFirstAction = true,
|
||||
onDismissRequest = onDismiss,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue