Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-24 12:36:51 +03:00
commit 808cd4a301
503 changed files with 12306 additions and 3036 deletions

View file

@ -68,9 +68,9 @@ fun CardWithIcon(
internal fun IconWithTitleAndDescription(
title: String,
description: String?,
iconBackground: Color = TangemTheme.colors.background.secondary,
icon: @Composable () -> Unit,
additionalContent: @Composable () -> Unit = {},
iconBackground: Color = TangemTheme.colors.background.secondary,
) {
Row(
modifier = Modifier

View file

@ -0,0 +1,94 @@
package com.tangem.core.ui.components
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.os.Build
import android.view.View
import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.tangem.core.ui.res.LocalIsInDarkTheme
@Composable
fun DialogFullScreen(
onDismissRequest: () -> Unit,
properties: DialogProperties = DialogProperties(),
content: @Composable () -> Unit,
) {
Dialog(
onDismissRequest = onDismissRequest,
properties = DialogProperties(
dismissOnBackPress = properties.dismissOnBackPress,
dismissOnClickOutside = properties.dismissOnClickOutside,
securePolicy = properties.securePolicy,
usePlatformDefaultWidth = true, // must be true as a part of work around
decorFitsSystemWindows = false,
),
content = {
val activityWindow = getActivityWindow()
val dialogWindow = getDialogWindow()
val parentView = LocalView.current.parent as View
SideEffect {
if (activityWindow != null && dialogWindow != null) {
val attributes = WindowManager.LayoutParams().apply {
copyFrom(activityWindow.attributes)
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
} else {
flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
}
type = dialogWindow.attributes.type
}
dialogWindow.attributes = attributes
parentView.layoutParams =
FrameLayout.LayoutParams(
activityWindow.decorView.width,
activityWindow.decorView.height,
)
}
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
val systemUiController = rememberSystemUiController(getActivityWindow())
val dialogSystemUiController = rememberSystemUiController(getDialogWindow())
SideEffect {
systemUiController.setSystemBarsColor(color = Color.Transparent)
dialogSystemUiController.setSystemBarsColor(color = Color.Transparent)
}
}
SystemBarsIconsDisposable(darkIcons = LocalIsInDarkTheme.current.not())
Surface(modifier = Modifier.fillMaxSize(), color = Color.Transparent) {
content()
}
},
)
}
// Window utils
@Composable
private fun getDialogWindow(): Window? = (LocalView.current.parent as? DialogWindowProvider)?.window
@Composable
private fun getActivityWindow(): Window? = LocalView.current.context.getActivityWindow()
private tailrec fun Context.getActivityWindow(): Window? = when (this) {
is Activity -> window
is ContextWrapper -> baseContext.getActivityWindow()
else -> null
}

View file

@ -75,7 +75,7 @@ fun Modifier.bottomFade(
)
enum class FadePosition {
TOP, BOTTOM, LEFT, RIGHT;
TOP, BOTTOM, LEFT, RIGHT
}
@Stable

View file

@ -169,12 +169,12 @@ private fun Preview_Tree() {
},
content = {
ArrowRowItems(
itemPadding = PaddingValues(vertical = TangemTheme.dimens.spacing4),
items = persistentListOf(
stringReference("Fist item"),
stringReference("Second item"),
stringReference("Third item"),
),
itemPadding = PaddingValues(vertical = TangemTheme.dimens.spacing4),
rootContent = {
PreviewItem(stringReference("Root"))
},

View file

@ -16,11 +16,11 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
inline fun <T : Any> InformationBlockContentScope.ListItems(
items: ImmutableList<T>,
itemContent: @Composable BoxScope.(T) -> Unit,
modifier: Modifier = Modifier,
itemPadding: PaddingValues = PaddingValues(all = TangemTheme.dimens.spacing0),
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
verticalArragement: Arrangement.Vertical = Arrangement.Top,
itemContent: @Composable BoxScope.(T) -> Unit,
) {
Column(
modifier = modifier.fillMaxWidth(),
@ -42,10 +42,10 @@ inline fun <T : Any> InformationBlockContentScope.ListItems(
@Composable
inline fun <T : Any> InformationBlockContentScope.GridItems(
items: ImmutableList<T>,
itemContent: @Composable BoxScope.(T) -> Unit,
modifier: Modifier = Modifier,
verticalAlignment: Alignment.Vertical = Alignment.Top,
horizontalArragement: Arrangement.Horizontal = Arrangement.Start,
itemContent: @Composable BoxScope.(T) -> Unit,
) {
val rowItems by remember(items) {
derivedStateOf {
@ -81,10 +81,10 @@ inline fun <T : Any> InformationBlockContentScope.GridItems(
@Composable
inline fun <T : Any> InformationBlockContentScope.ArrowRowItems(
items: ImmutableList<T>,
rootContent: @Composable BoxScope.() -> Unit,
itemContent: @Composable BoxScope.(T) -> Unit,
modifier: Modifier = Modifier,
itemPadding: PaddingValues = PaddingValues(all = TangemTheme.dimens.spacing0),
rootContent: @Composable BoxScope.() -> Unit,
itemContent: @Composable BoxScope.(T) -> Unit,
) {
Column(
modifier = modifier.fillMaxWidth(),

View file

@ -48,10 +48,10 @@ const val MODAL_SHEET_MAX_HEIGHT = 0.8f
inline fun <reified T : TangemBottomSheetConfigContent> TangemModalBottomSheet(
config: TangemBottomSheetConfig,
containerColor: Color = TangemTheme.colors.background.primary,
noinline onBack: (() -> Unit)? = null,
skipPartiallyExpanded: Boolean = true,
dismissOnClickOutside: Boolean = true,
scrollableContent: Boolean = true,
noinline onBack: (() -> Unit)? = null,
crossinline title: @Composable BoxScope.(T) -> Unit = {},
crossinline content: @Composable ColumnScope.(T) -> Unit,
) {
@ -202,9 +202,9 @@ inline fun <reified T : TangemBottomSheetConfigContent> BsContent(
inline fun <reified T : TangemBottomSheetConfigContent> BasicModalBottomSheet(
config: TangemBottomSheetConfig,
sheetState: SheetState,
modifier: Modifier = Modifier,
noinline onBack: (() -> Unit)? = null,
noinline bsContent: @Composable ColumnScope.() -> Unit,
modifier: Modifier = Modifier,
) {
if (onBack != null) {
ModalBottomSheetWithBackHandling(

View file

@ -143,11 +143,11 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicModalBottomSheetWit
config: TangemBottomSheetConfig,
sheetState: SheetState,
containerColor: Color,
modifier: Modifier = Modifier,
noinline onBack: (() -> Unit)? = null,
crossinline title: @Composable BoxScope.(T) -> Unit,
crossinline content: @Composable (T) -> Unit,
noinline footer: @Composable (BoxScope.(T) -> Unit)?,
modifier: Modifier = Modifier,
) {
val model = config.content as? T ?: return

View file

@ -152,10 +152,10 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicBottomSheet(
sheetState: SheetState,
containerColor: Color,
addBottomInsets: Boolean,
modifier: Modifier = Modifier,
noinline onBack: (() -> Unit)? = null,
crossinline title: @Composable (BoxScope.(T) -> Unit),
crossinline content: @Composable (ColumnScope.(T) -> Unit),
modifier: Modifier = Modifier,
) {
val model = config.content as? T ?: return

View file

@ -22,7 +22,7 @@ import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
import com.tangem.core.ui.test.BaseActionButtonsBlockTestTags
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -36,7 +36,7 @@ fun HorizontalActionChips(
LazyRow(
modifier = modifier
.fillMaxWidth()
.testTag(TokenDetailsScreenTestTags.HORIZONTAL_ACTION_CHIPS),
.testTag(BaseActionButtonsBlockTestTags.HORIZONTAL_ACTION_CHIPS),
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8),
verticalAlignment = Alignment.CenterVertically,
contentPadding = contentPadding,

View file

@ -34,7 +34,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
import com.tangem.core.ui.test.BaseActionButtonsBlockTestTags
/**
* Rounded action button
@ -100,7 +100,7 @@ fun ActionButton(
),
)
},
modifier = modifier.testTag(TokenDetailsScreenTestTags.ACTION_BUTTON),
modifier = modifier,
color = color,
containerColor = containerColor,
)
@ -111,10 +111,10 @@ fun ActionButton(
fun ActionBaseButton(
config: ActionButtonConfig,
shape: RoundedCornerShape,
content: @Composable (modifier: Modifier) -> Unit,
modifier: Modifier = Modifier,
color: Color = TangemTheme.colors.button.secondary,
containerColor: Color = TangemTheme.colors.background.secondary,
content: @Composable (modifier: Modifier) -> Unit,
) {
val context = LocalContext.current
val backgroundColor by animateColorAsState(
@ -145,7 +145,8 @@ fun ActionBaseButton(
}
},
)
.background(color = backgroundColor),
.background(color = backgroundColor)
.testTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON),
) {
content(Modifier.align(Alignment.Center))
@ -163,9 +164,9 @@ fun ActionBaseButton(
@Composable
fun ActionButtonContent(
config: ActionButtonConfig,
text: @Composable (Color) -> Unit,
modifier: Modifier = Modifier,
paddingBetweenIconAndText: Dp = 8.dp,
text: @Composable (Color) -> Unit,
) {
Row(
modifier = modifier

View file

@ -24,8 +24,8 @@ internal inline fun DefaultCurrencyIcon(
size: Dp,
alpha: Float,
colorFilter: ColorFilter?,
crossinline errorIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
crossinline errorIcon: @Composable () -> Unit,
) {
var iconBackgroundColor by remember { mutableStateOf(Color.Transparent) }
var isBackgroundColorDefined by remember { mutableStateOf(false) }

View file

@ -113,8 +113,8 @@ private fun TokenIcon(
url: String?,
alpha: Float,
colorFilter: ColorFilter?,
errorIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
errorIcon: @Composable () -> Unit,
) {
if (url == null) {
errorIcon()

View file

@ -103,11 +103,11 @@ fun SearchBar(
@OptIn(ExperimentalMaterial3Api::class)
private fun DecorationBox(
state: SearchBarUM,
innerTextField: @Composable () -> Unit,
interactionSource: MutableInteractionSource,
colors: TextFieldColors,
focusManager: FocusManager,
keyboardController: SoftwareKeyboardController?,
innerTextField: @Composable () -> Unit,
) {
TextFieldDefaults.DecorationBox(
value = state.query,

View file

@ -121,12 +121,12 @@ fun SimpleTextField(
@Composable
private fun SimpleTextPlaceholder(
placeholder: TextReference?,
value: String,
textStyle: TextStyle,
centered: Boolean,
textValue: @Composable () -> Unit,
placeholder: TextReference?,
color: Color = TangemTheme.colors.text.disabled,
textValue: @Composable () -> Unit,
) {
Box(contentAlignment = if (centered) Alignment.Center else Alignment.TopStart) {
if (value.isBlank() && placeholder != null) {

View file

@ -0,0 +1,10 @@
package com.tangem.core.ui.components.icons
import androidx.compose.runtime.Stable
@Stable
enum class IconTint {
Accent,
Warning,
Inactive,
}

View file

@ -58,8 +58,8 @@ internal data class Blockies(
}
private fun dataFromSeed(seed: MutableList<Long>) = MutableList(SIZE * SIZE) { DEFAULT_VALUE_F }.apply {
(0 until SIZE).forEach { row ->
(0 until HALF_SIZE).forEach { column ->
for (row in 0 until SIZE) {
for (column in 0 until HALF_SIZE) {
val value = floor(nextSeed(seed) * PROBABILITY_COLOR)
this[row * SIZE + column] = value
this[(row + 1) * SIZE - column - 1] = value

View file

@ -21,9 +21,9 @@ import com.tangem.core.ui.utils.*
@Composable
inline fun ArrowRow(
isLastItem: Boolean,
content: @Composable() (BoxScope.() -> Unit),
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(all = TangemTheme.dimens.spacing0),
content: @Composable() (BoxScope.() -> Unit),
) {
val density = LocalDensity.current.density
val defaultRowHeight = TangemTheme.dimens.size0

View file

@ -27,7 +27,7 @@ private const val DISABLED_ICON_ALPHA = 0.4f
* [Figma Component](https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2737-2800&t=ewlXfWwbDnRhjw4B-4)
* */
@Composable
fun BlockchainRow(model: BlockchainRowUM, action: @Composable BoxScope.() -> Unit, modifier: Modifier = Modifier) {
fun BlockchainRow(model: BlockchainRowUM, modifier: Modifier = Modifier, action: @Composable BoxScope.() -> Unit) {
RowContentContainer(
modifier = modifier
.heightIn(min = TangemTheme.dimens.size52)

View file

@ -53,10 +53,10 @@ fun ChainRow(model: ChainRowUM, modifier: Modifier = Modifier, action: @Composab
@Composable
inline fun ChainRowContainer(
modifier: Modifier = Modifier,
icon: @Composable BoxScope.() -> Unit,
text: @Composable BoxScope.() -> Unit,
action: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
) {
RowContentContainer(
modifier = modifier

View file

@ -29,8 +29,8 @@ import com.tangem.core.ui.res.TangemThemePreview
*/
@Composable
fun NetworkTitle(
title: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
title: @Composable BoxScope.() -> Unit,
action: (@Composable BoxScope.() -> Unit)? = null,
) {
val minHeight = if (action == null) TangemTheme.dimens.size36 else TangemTheme.dimens.size40

View file

@ -13,11 +13,11 @@ import com.tangem.core.ui.res.TangemTheme
@Composable
inline fun RowContentContainer(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
icon: @Composable BoxScope.() -> Unit,
text: @Composable BoxScope.() -> Unit,
action: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
Row(
modifier = modifier.fillMaxWidth(),

View file

@ -122,16 +122,18 @@ fun ShowcaseButtons(
private fun Showcase_Preview() {
TangemThemePreview {
Showcase(
headerIconRes = R.drawable.ic_notifications_unread_24,
headerIconRes = R.drawable.ic_notification_56,
headerText = resourceReference(R.string.user_push_notification_agreement_header),
showcaseItems = persistentListOf(
ShowcaseItemModel(
R.drawable.ic_rocket_launch_24,
resourceReference(R.string.user_push_notification_agreement_argument_one),
iconRes = R.drawable.ic_rocket_launch_24,
title = resourceReference(R.string.user_push_notification_agreement_argument_one_title),
subTitle = resourceReference(R.string.user_push_notification_agreement_argument_one_subtitle),
),
ShowcaseItemModel(
R.drawable.ic_storefront_24,
resourceReference(R.string.user_push_notification_agreement_argument_two),
iconRes = R.drawable.ic_storefront_24,
title = resourceReference(R.string.user_push_notification_agreement_argument_two_title),
subTitle = resourceReference(R.string.user_push_notification_agreement_argument_two_subtitle),
),
),
primaryButton = ShowcaseButtonModel(resourceReference(R.string.common_allow), {}),

View file

@ -63,7 +63,8 @@ fun ShowcaseContent(
repeat(showcaseItems.size) { index ->
ShowcaseItem(
iconRes = showcaseItems[index].iconRes,
text = showcaseItems[index].text,
title = showcaseItems[index].title,
subtitle = showcaseItems[index].subTitle,
)
}
}

View file

@ -1,33 +1,47 @@
package com.tangem.core.ui.components.showcase
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
@Composable
internal fun ShowcaseItem(@DrawableRes iconRes: Int, text: TextReference) {
Row {
internal fun ShowcaseItem(@DrawableRes iconRes: Int, title: TextReference, subtitle: TextReference) {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
tint = TangemTheme.colors.icon.primary1,
)
Text(
text = text.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
Column(
modifier = Modifier
.fillMaxWidth()
.padding(start = TangemTheme.dimens.spacing20),
)
verticalArrangement = Arrangement.spacedBy(3.dp),
) {
Text(
text = title.resolveReference(),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
modifier = Modifier.fillMaxWidth(),
)
Text(
text = subtitle.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier.fillMaxWidth(),
)
}
}
}

View file

@ -5,5 +5,6 @@ import com.tangem.core.ui.extensions.TextReference
data class ShowcaseItemModel(
@DrawableRes val iconRes: Int,
val text: TextReference,
val title: TextReference,
val subTitle: TextReference,
)

View file

@ -22,6 +22,7 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.audits.AuditLabelUM
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.icons.IconTint
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.components.token.internal.*
import com.tangem.core.ui.components.token.state.TokenItemState
@ -488,7 +489,14 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
fiatAmountState = FiatAmountState.Content(
text = "3213123123321312312312312312 $",
icons = persistentListOf(
FiatAmountState.Content.IconUM(R.drawable.ic_error_sync_24, useAccentColor = false),
FiatAmountState.Content.IconUM(
iconRes = R.drawable.img_attention_20,
tint = IconTint.Warning,
),
FiatAmountState.Content.IconUM(
iconRes = R.drawable.ic_error_sync_24,
tint = IconTint.Inactive,
),
stakingIcon,
),
isFlickering = true,
@ -534,7 +542,10 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
TokenItemState.Draggable(
id = UUID.randomUUID().toString(),
iconState = tokenIconState,
titleState = TokenItemState.TitleState.Content(text = stringReference(value = "Polygon")),
titleState = TokenItemState.TitleState.Content(
text = stringReference(value = "Polygon"),
earnApy = stringReference("Earn 5%"),
),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "3 172,14 $"),
),
TokenItemState.Content(
@ -603,7 +614,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
companion object {
val stakingIcon = FiatAmountState.Content.IconUM(R.drawable.ic_staking_24, useAccentColor = true)
val stakingIcon = FiatAmountState.Content.IconUM(R.drawable.ic_staking_24, tint = IconTint.Accent)
val coinIconState
get() = CurrencyIconState.CoinIcon(

View file

@ -18,6 +18,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.icons.IconTint
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.extensions.orMaskWithStars
import com.tangem.core.ui.res.TangemTheme
@ -75,10 +76,10 @@ private fun ContentFiatAmount(
Icon(
modifier = Modifier.size(12.dp),
painter = rememberVectorPainter(image = ImageVector.vectorResource(icon.iconRes)),
tint = if (icon.useAccentColor) {
TangemTheme.colors.icon.accent
} else {
TangemTheme.colors.icon.inactive
tint = when (icon.tint) {
IconTint.Accent -> TangemTheme.colors.icon.accent
IconTint.Warning -> TangemTheme.colors.icon.attention
IconTint.Inactive -> TangemTheme.colors.icon.inactive
},
contentDescription = null,
)

View file

@ -2,7 +2,9 @@ package com.tangem.core.ui.components.token.internal
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@ -13,8 +15,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.components.token.state.TokenItemState.TitleState as TokenTitleState
@ -56,6 +60,11 @@ private fun ContentTitle(state: TokenTitleState.Content, modifier: Modifier = Mo
hasPending = state.hasPending,
modifier = Modifier.align(alignment = Alignment.CenterVertically),
)
YieldSupplyApyLabel(
apy = state.earnApy,
modifier = Modifier.align(alignment = Alignment.CenterVertically),
)
}
}
@ -71,6 +80,25 @@ private fun CurrencyNameText(name: String, isAvailable: Boolean, modifier: Modif
)
}
@Composable
private fun YieldSupplyApyLabel(apy: TextReference?, modifier: Modifier = Modifier) {
AnimatedVisibility(visible = apy != null, modifier = modifier) {
Box(
modifier = modifier.background(
color = TangemTheme.colors.text.accent.copy(alpha = 0.1f),
shape = TangemTheme.shapes.roundedCornersSmall2,
),
) {
Text(
text = apy?.resolveReference().orEmpty(),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.accent,
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
)
}
}
}
@Composable
private fun PendingTransactionImage(hasPending: Boolean, modifier: Modifier = Modifier) {
AnimatedVisibility(visible = hasPending, modifier = modifier) {

View file

@ -3,6 +3,7 @@ package com.tangem.core.ui.components.token.state
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.audits.AuditLabelUM
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.icons.IconTint
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.ImmutableList
@ -167,6 +168,7 @@ sealed class TokenItemState {
val text: TextReference,
val hasPending: Boolean = false,
val isAvailable: Boolean = true,
val earnApy: TextReference? = null,
) : TitleState()
data object Loading : TitleState()
@ -204,7 +206,7 @@ sealed class TokenItemState {
data class IconUM(
val iconRes: Int,
val useAccentColor: Boolean,
val tint: IconTint = IconTint.Inactive,
)
}

View file

@ -24,9 +24,9 @@ import kotlinx.coroutines.launch
@Composable
fun TangemTooltip(
text: String,
content: @Composable (Modifier) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
content: @Composable (Modifier) -> Unit,
) {
InternalTangemTooltip(
modifier = modifier,
@ -46,9 +46,9 @@ fun TangemTooltip(
@Composable
fun TangemTooltip(
text: AnnotatedString,
content: @Composable (Modifier) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
content: @Composable (Modifier) -> Unit,
) {
InternalTangemTooltip(
modifier = modifier,
@ -68,10 +68,10 @@ fun TangemTooltip(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun InternalTangemTooltip(
tooltipContent: @Composable () -> Unit,
content: @Composable (Modifier) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
tooltipContent: @Composable () -> Unit,
content: @Composable (Modifier) -> Unit,
) {
val tooltipState = rememberTooltipState(isPersistent = true)
val coroutineScope = rememberCoroutineScope()

View file

@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -18,6 +19,7 @@ import com.tangem.core.ui.components.buttons.actions.ActionButton
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.EmptyTransactionBlockTestTags
/**
* Placeholder for transaction's block without content
@ -31,19 +33,24 @@ fun EmptyTransactionBlock(state: EmptyTransactionsBlockState, modifier: Modifier
modifier = modifier
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(color = TangemTheme.colors.background.primary)
.padding(vertical = TangemTheme.dimens.spacing24),
.padding(vertical = TangemTheme.dimens.spacing24)
.testTag(EmptyTransactionBlockTestTags.BLOCK),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size64),
modifier = Modifier
.size(TangemTheme.dimens.size64)
.testTag(EmptyTransactionBlockTestTags.ICON),
painter = painterResource(id = state.iconRes),
tint = TangemTheme.colors.icon.inactive,
contentDescription = null,
)
Text(
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing32),
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing32)
.testTag(EmptyTransactionBlockTestTags.TEXT),
textAlign = TextAlign.Center,
text = state.text.resolveReference(),
style = TangemTheme.typography.body2,
@ -51,7 +58,9 @@ fun EmptyTransactionBlock(state: EmptyTransactionsBlockState, modifier: Modifier
)
Buttons(
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing18),
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing18)
.testTag(EmptyTransactionBlockTestTags.EXPLORE_BUTTON),
state = state.buttonsState,
)
}

View file

@ -10,13 +10,16 @@ interface ComposableBottomSheetComponent {
@Composable
fun BottomSheet()
}
fun getEmptyComposableBottomSheetComponent() = EmptyComposableBottomSheetComponent
companion object {
val EMPTY = EmptyComposableBottomSheetComponent
}
}
object EmptyComposableBottomSheetComponent : ComposableBottomSheetComponent {
override fun dismiss() {}
@Composable
override fun BottomSheet() {}
override fun BottomSheet() {
}
}

View file

@ -9,9 +9,11 @@ fun interface ComposableContentComponent {
@Composable
fun Content(modifier: Modifier)
}
fun getEmptyComposableContentComponent() = EmptyComposableContentComponent
companion object {
val EMPTY = EmptyComposableContentComponent
}
}
object EmptyComposableContentComponent : ComposableContentComponent {
@Composable

View file

@ -15,9 +15,11 @@ interface ComposableModularContentComponent {
@Composable
fun Footer()
}
fun getEmptyComposableModularContentComponent() = EmptyComposableModularContentComponent
companion object {
val EMPTY = EmptyComposableModularContentComponent
}
}
object EmptyComposableModularContentComponent : ComposableModularContentComponent {
@Composable

View file

@ -52,10 +52,10 @@ fun TangemTheme(
@Composable
fun TangemTheme(
isDark: Boolean = false,
windowSize: WindowSize,
typography: TangemTypography = TangemTheme.typography,
dimens: TangemDimens = TangemTheme.dimens,
isDark: Boolean = false,
vibratorHapticManager: VibratorHapticManager? = null,
eventMessageHandler: EventMessageHandler = remember { EventMessageHandler() },
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },

View file

@ -1,11 +1,53 @@
package com.tangem.core.ui.security
import android.app.Activity
import android.view.WindowManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.platform.LocalContext
import com.tangem.core.ui.utils.findActivity
import timber.log.Timber
private val LocalSecureFlagController = staticCompositionLocalOf<SecureFlagController> {
error("No SecureFlagController provided")
}
private class SecureFlagController(private val activity: Activity) {
private var count by mutableIntStateOf(0)
fun enable() {
if (count == 0) {
activity.window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE,
)
}
count++
}
fun disable() {
count--
if (count == 0) {
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}
}
@Composable
fun ProvideSecureFlagController(content: @Composable () -> Unit) {
val activity = LocalContext.current.findActivity()
val controller = remember(activity) { SecureFlagController(activity) }
CompositionLocalProvider(
LocalSecureFlagController provides controller,
content = content,
)
}
/**
* Disables screenshots for the current composition.
@ -14,18 +56,10 @@ import timber.log.Timber
*/
@Composable
fun DisableScreenshotsDisposableEffect() {
val activity = LocalContext.current.findActivity()
val secureFlagController = LocalSecureFlagController.current
DisposableEffect(activity) {
Timber.d("Security mode: enabled")
activity.window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE,
)
onDispose {
Timber.d("Security mode: disabled")
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
DisposableEffect(secureFlagController) {
secureFlagController.enable()
onDispose { secureFlagController.disable() }
}
}

View file

@ -0,0 +1,6 @@
package com.tangem.core.ui.test
object BaseActionButtonsBlockTestTags {
const val HORIZONTAL_ACTION_CHIPS = "BASE_ACTION_BUTTONS_BLOCK_HORIZONTAL_ACTION_CHIPS"
const val ACTION_BUTTON = "BASE_ACTION_BUTTONS_BLOCK_ACTION_BUTTON"
}

View file

@ -0,0 +1,8 @@
package com.tangem.core.ui.test
object EmptyTransactionBlockTestTags {
const val BLOCK = "EMPTY_TRANSACTION_BLOCK"
const val ICON = "EMPTY_TRANSACTION_BLOCK_ICON"
const val TEXT = "EMPTY_TRANSACTION_BLOCK_TEXT"
const val EXPLORE_BUTTON = "EMPTY_TRANSACTION_BLOCK_EXPLORE_BUTTON"
}

View file

@ -7,9 +7,9 @@ object MainScreenTestTags {
const val TOKEN_LIST_ITEM = "MAIN_SCREEN_TOKEN_LIST_ITEM"
const val WALLET_LIST_ITEM = "MAIN_SCREEN_WALLET_LIST_ITEM"
const val ORGANIZE_TOKENS_BUTTON = "MAIN_SCREEN_ORGANIZE_TOKENS_BUTTON"
const val MULTI_CURRENCY_ACTION_BUTTON = "MAIN_SCREEN_MULTI_CURRENCY_ACTION_BUTTON"
const val CARD_TITLE = "MAIN_SCREEN_CARD_TITLE"
const val CARD_IMAGE = "MAIN_SCREEN_CARD_IMAGE"
const val DEVICES_COUNT = "MAIN_SCREEN_DEVICES_COUNT"
const val WALLET_BALANCE = "MAIN_SCREEN_WALLET_BALANCE"
const val TOTAL_BALANCE_MENU_ITEM = "MAIN_SCREEN_TOTAL_BALANCE_MENU_ITEM"

View file

@ -6,4 +6,6 @@ object StoriesScreenTestTags {
const val ORDER_BUTTON = "STORIES_SCREEN_ORDER_BUTTON"
const val CREATE_NEW_WALLET_BUTTON = "STORIES_SCREEN_CREATE_NEW_WALLET_BUTTON"
const val ADD_EXISTING_WALLET_BUTTON = "STORIES_SCREEN_ADD_EXISTING_WALLET_BUTTON"
const val TITLE = "STORIES_SCREEN_TITLE"
const val TEXT = "STORIES_SCREEN_TEXT"
}

View file

@ -4,8 +4,6 @@ object TokenDetailsScreenTestTags {
const val SCREEN_CONTAINER = "TOKEN_DETAILS_SCREEN_CONTAINER"
const val TOKEN_TITLE = "TOKEN_DETAILS_SCREEN_TOKEN_TITLE"
const val ACTION_BUTTON = "TOKEN_DETAILS_SCREEN_ACTION_BUTTON"
const val HORIZONTAL_ACTION_CHIPS = "TOKEN_DETAILS_SCREEN_HORIZONTAL_ACTION_CHIPS"
const val STAKING_BLOCK = "TOKEN_DETAILS_SCREEN_STAKING_BLOCK"
const val STAKING_AVAILABLE_BLOCK = "TOKEN_DETAILS_SCREEN_STAKING_AVAILABLE_BLOCK"

View file

@ -64,9 +64,7 @@ fun DecimalFormat.getValidatedNumberWithFixedDecimals(text: String, decimals: In
val beforeDecimal = filteredChars.substringBefore(decimalSeparator)
val afterDecimal = filteredChars.substringAfter(decimalSeparator)
decimals.getWithIntegerDecimals(beforeDecimal, decimalSeparator, afterDecimal)
}
// If there is no dot, just take all digits
else {
} else { // If there is no dot, just take all digits
filteredChars
}
}
@ -87,9 +85,7 @@ fun DecimalFormat.formatWithThousands(text: String, decimals: Int): String {
.reversed()
val afterDecimal = localizedText.substringAfter(decimalSeparator)
decimals.getWithIntegerDecimals(beforeDecimal, decimalSeparator, afterDecimal)
}
// If there is no dot, just take all digits
else {
} else { // If there is no dot, just take all digits
localizedText.reversed()
.chunked(TEXT_CHUNK_THOUSAND)
.joinToString(thousandsSeparator.toString())

View file

@ -44,9 +44,7 @@ class InputNumberFormatter(
val beforeDecimal = filteredChars.substringBefore(decimalSeparator)
val afterDecimal = filteredChars.substringAfter(decimalSeparator)
beforeDecimal + decimalSeparator + afterDecimal.take(decimals)
}
// If there is no dot, just take all digits
else {
} else { // If there is no dot, just take all digits
filteredChars
}
}
@ -62,9 +60,7 @@ class InputNumberFormatter(
.reversed()
val afterDecimal = text.substringAfter(decimalSeparator)
beforeDecimal + decimalSeparator + afterDecimal.take(decimals)
}
// If there is no dot, just take all digits
else {
} else { // If there is no dot, just take all digits
text.reversed()
.chunked(TEXT_CHUNK_THOUSAND)
.joinToString(thousandsSeparator.toString())

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<path
android:pathData="M5.353,1.622C5.641,1.123 6.362,1.123 6.65,1.622L10.85,8.875C11.139,9.375 10.778,10.001 10.2,10.001H1.802C1.224,10.001 0.864,9.375 1.153,8.875L5.353,1.622ZM5.502,8.002V9.002H6.502V8.002H5.502ZM5.502,4.002V7.002H6.502V4.002H5.502Z"
android:fillColor="#000000"/>
</vector>

View file

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="56dp"
android:height="56dp"
android:viewportWidth="56"
android:viewportHeight="56">
<path
android:pathData="M10.289,26.72C10.784,17.3 18.567,9.917 28,9.917C37.433,9.917 45.216,17.3 45.711,26.72C45.733,27.123 45.748,27.508 45.764,27.879L45.764,27.88C45.815,29.143 45.86,30.243 46.089,31.298C46.363,32.557 46.869,33.548 47.898,34.32C49.694,35.666 50.75,37.779 50.75,40.023C50.75,43.246 48.213,46.083 44.8,46.083H11.2C7.787,46.083 5.25,43.246 5.25,40.023C5.25,37.779 6.306,35.666 8.102,34.32C9.131,33.548 9.637,32.557 9.911,31.298C10.14,30.243 10.185,29.143 10.236,27.88L10.236,27.88C10.252,27.508 10.267,27.123 10.289,26.72Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M24.567,3.207C25.605,2.527 26.873,2.333 28,2.333C29.127,2.333 30.395,2.527 31.433,3.207C32.586,3.961 33.25,5.182 33.25,6.708C33.25,8.099 32.706,9.552 31.879,10.665C31.065,11.76 29.73,12.833 28,12.833C26.27,12.833 24.935,11.76 24.121,10.665C23.294,9.552 22.75,8.099 22.75,6.708C22.75,5.182 23.414,3.961 24.567,3.207Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M21,42C22.288,42 23.333,43.045 23.333,44.333C23.333,46.911 25.423,49 28,49C30.577,49 32.667,46.911 32.667,44.333C32.667,43.045 33.711,42 35,42C36.289,42 37.333,43.045 37.333,44.333C37.333,49.488 33.154,53.667 28,53.667C22.845,53.667 18.667,49.488 18.667,44.333C18.667,43.045 19.711,42 21,42Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="25dp"
android:viewportWidth="24"
android:viewportHeight="25">
<path
android:pathData="M14.75,5.75C14.75,3.541 16.541,1.75 18.75,1.75C20.959,1.75 22.75,3.541 22.75,5.75C22.75,7.959 20.959,9.75 18.75,9.75C16.541,9.75 14.75,7.959 14.75,5.75Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M12.663,2.75C13.279,2.75 13.587,2.75 13.707,2.914C13.827,3.078 13.72,3.412 13.508,4.08C13.34,4.607 13.25,5.168 13.25,5.75C13.25,8.788 15.712,11.25 18.75,11.25C19.339,11.25 19.907,11.157 20.44,10.985C21.091,10.775 21.418,10.671 21.582,10.79C21.746,10.91 21.747,11.209 21.749,11.809C21.75,12.172 21.75,12.55 21.75,12.942V13.058C21.75,15.248 21.75,16.968 21.569,18.312C21.384,19.688 20.997,20.781 20.139,21.639C19.281,22.497 18.188,22.884 16.812,23.069C15.468,23.25 13.748,23.25 11.558,23.25H11.442C9.252,23.25 7.532,23.25 6.188,23.069C4.812,22.884 3.72,22.497 2.861,21.639C2.003,20.781 1.616,19.688 1.431,18.312C1.25,16.968 1.25,15.248 1.25,13.058V12.942C1.25,10.752 1.25,9.032 1.431,7.688C1.616,6.312 2.003,5.22 2.861,4.361C3.72,3.503 4.812,3.116 6.188,2.931C7.532,2.75 9.252,2.75 11.442,2.75H12.663ZM7,15.75C6.586,15.75 6.25,16.086 6.25,16.5C6.25,16.914 6.586,17.25 7,17.25H15C15.414,17.25 15.75,16.914 15.75,16.5C15.75,16.086 15.414,15.75 15,15.75H7ZM7,10.75C6.586,10.75 6.25,11.086 6.25,11.5C6.25,11.914 6.586,12.25 7,12.25H11C11.414,12.25 11.75,11.914 11.75,11.5C11.75,11.086 11.414,10.75 11,10.75H7Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:strokeAlpha="0.1"
android:fillColor="#0099FF"
android:fillAlpha="0.1"/>
<path
android:pathData="M17.758,21.123C18.172,21.12 18.51,21.453 18.514,21.867C18.517,22.281 18.184,22.619 17.771,22.623C16.646,22.633 15.542,23.074 14.779,23.887C14.496,24.189 14.021,24.203 13.719,23.92C13.417,23.636 13.402,23.161 13.686,22.859C14.756,21.719 16.265,21.136 17.758,21.123ZM18.982,17.373C18.982,16.671 18.425,16.123 17.764,16.123C17.102,16.123 16.546,16.672 16.546,17.373C16.546,18.075 17.102,18.623 17.764,18.623C18.425,18.623 18.982,18.075 18.982,17.373ZM20.482,17.373C20.482,18.881 19.276,20.123 17.764,20.123C16.251,20.123 15.046,18.881 15.046,17.373C15.046,15.866 16.251,14.623 17.764,14.623C19.276,14.623 20.482,15.866 20.482,17.373Z"
android:fillColor="#0099FF"/>
<path
android:pathData="M8.482,20.742V16.006C8.482,14.465 8.481,13.23 8.618,12.262C8.759,11.268 9.06,10.447 9.742,9.801C10.346,9.229 11.088,8.946 11.974,8.799C12.841,8.655 13.915,8.63 15.229,8.625C15.644,8.624 15.981,8.958 15.982,9.372C15.984,9.786 15.649,10.123 15.235,10.125C13.905,10.13 12.95,10.157 12.22,10.278C11.508,10.397 11.086,10.594 10.773,10.89C10.431,11.215 10.219,11.661 10.104,12.473C9.985,13.311 9.982,14.421 9.982,16.006V20.742C9.982,22.328 9.985,23.437 10.104,24.275C10.219,25.087 10.431,25.534 10.773,25.858C11.122,26.189 11.61,26.397 12.486,26.509C13.381,26.623 14.562,26.624 16.232,26.624H18.232C18.647,26.624 18.982,26.96 18.982,27.374C18.982,27.788 18.647,28.124 18.232,28.124H16.232C14.603,28.124 13.308,28.125 12.297,27.996C11.268,27.865 10.418,27.588 9.742,26.947C9.06,26.301 8.759,25.48 8.618,24.486C8.481,23.519 8.482,22.283 8.482,20.742ZM25.482,16.874V16.006C25.482,14.421 25.48,13.311 25.361,12.473C25.246,11.661 25.034,11.215 24.691,10.89C24.379,10.594 23.956,10.397 23.245,10.278C22.515,10.157 21.56,10.13 20.229,10.125C19.815,10.123 19.481,9.786 19.482,9.372C19.484,8.958 19.821,8.624 20.235,8.625C21.549,8.63 22.624,8.655 23.491,8.799C24.377,8.946 25.119,9.229 25.723,9.801C26.405,10.447 26.706,11.268 26.847,12.262C26.984,13.23 26.982,14.465 26.982,16.006V16.874C26.982,17.288 26.647,17.624 26.232,17.624C25.818,17.624 25.483,17.288 25.482,16.874Z"
android:fillColor="#0099FF"/>
<path
android:pathData="M17.733,6.623C18.164,6.623 18.503,6.618 18.81,6.689C19.473,6.841 20.057,7.255 20.383,7.855C20.536,8.136 20.606,8.466 20.691,8.836L20.774,9.195C20.856,9.547 20.931,9.869 20.964,10.138C20.998,10.417 21,10.74 20.854,11.062C20.704,11.391 20.455,11.659 20.153,11.843C19.867,12.016 19.558,12.073 19.27,12.099C18.986,12.124 18.634,12.123 18.231,12.123H17.235C16.831,12.123 16.48,12.124 16.195,12.099C15.907,12.073 15.598,12.016 15.313,11.843C15.01,11.659 14.761,11.391 14.611,11.062C14.465,10.74 14.467,10.417 14.501,10.138C14.534,9.869 14.609,9.547 14.691,9.195L14.774,8.836C14.859,8.466 14.929,8.136 15.082,7.855C15.408,7.255 15.992,6.841 16.655,6.689C16.962,6.618 17.301,6.623 17.733,6.623ZM17.733,8.123C17.223,8.123 17.092,8.128 16.992,8.15C16.71,8.215 16.503,8.382 16.399,8.571C16.368,8.629 16.342,8.714 16.236,9.174L16.153,9.534C16.064,9.918 16.011,10.148 15.99,10.318C15.981,10.391 15.982,10.432 15.983,10.45C16.002,10.486 16.035,10.527 16.091,10.562C16.092,10.562 16.095,10.563 16.098,10.564C16.104,10.567 16.115,10.571 16.133,10.575C16.17,10.585 16.23,10.596 16.326,10.605C16.53,10.622 16.804,10.623 17.235,10.623H18.231C18.661,10.623 18.935,10.622 19.139,10.605C19.235,10.596 19.295,10.585 19.332,10.575C19.35,10.571 19.361,10.567 19.367,10.564C19.37,10.563 19.372,10.562 19.373,10.562C19.429,10.528 19.462,10.486 19.481,10.45C19.482,10.432 19.484,10.392 19.475,10.318C19.454,10.148 19.401,9.918 19.313,9.534L19.23,9.174C19.123,8.714 19.097,8.629 19.066,8.571C18.962,8.382 18.755,8.215 18.473,8.15C18.373,8.128 18.242,8.123 17.733,8.123Z"
android:fillColor="#0099FF"/>
<path
android:pathData="M27.483,23.373C27.483,21.578 26.028,20.123 24.233,20.123C22.438,20.123 20.983,21.578 20.983,23.373C20.983,25.168 22.438,26.623 24.233,26.623C26.028,26.623 27.483,25.168 27.483,23.373ZM22.572,24.493H22.574L22.575,24.494C22.202,24.316 22.045,23.868 22.223,23.494C22.401,23.121 22.848,22.963 23.222,23.141L23.224,23.142L23.227,23.143C23.228,23.143 23.23,23.145 23.232,23.146C23.235,23.147 23.24,23.149 23.244,23.151C23.253,23.156 23.265,23.162 23.278,23.169C23.303,23.183 23.337,23.202 23.376,23.226C23.451,23.272 23.549,23.338 23.658,23.426C23.669,23.409 23.68,23.393 23.691,23.376C24.021,22.875 24.552,22.178 25.21,21.824C25.575,21.628 26.03,21.764 26.227,22.129C26.423,22.494 26.286,22.948 25.921,23.145C25.618,23.308 25.26,23.722 24.942,24.203C24.795,24.427 24.673,24.637 24.589,24.791C24.547,24.868 24.515,24.93 24.493,24.972C24.483,24.993 24.475,25.009 24.47,25.019C24.467,25.024 24.466,25.027 24.465,25.029C24.345,25.279 24.097,25.444 23.82,25.456C23.544,25.468 23.282,25.326 23.142,25.087C23.005,24.855 22.847,24.698 22.729,24.603C22.67,24.555 22.622,24.523 22.593,24.505L22.572,24.493ZM28.983,23.373C28.983,25.997 26.856,28.123 24.233,28.123C21.609,28.123 19.483,25.997 19.483,23.373C19.483,20.75 21.609,18.623 24.233,18.623C26.856,18.623 28.983,20.75 28.983,23.373Z"
android:fillColor="#0099FF"/>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="25dp"
android:viewportWidth="24"
android:viewportHeight="25">
<path
android:pathData="M12,2.75C12.414,2.75 12.75,3.086 12.75,3.5C12.75,5.506 13.761,7.575 15.343,9.157C16.925,10.739 18.994,11.75 21,11.75C21.414,11.75 21.75,12.086 21.75,12.5C21.75,12.914 21.414,13.25 21,13.25C18.994,13.25 16.925,14.261 15.343,15.843C13.761,17.425 12.75,19.494 12.75,21.5C12.75,21.914 12.414,22.25 12,22.25C11.586,22.25 11.25,21.914 11.25,21.5C11.25,19.494 10.239,17.425 8.657,15.843C7.075,14.261 5.006,13.25 3,13.25C2.586,13.25 2.25,12.914 2.25,12.5C2.25,12.086 2.586,11.75 3,11.75C5.006,11.75 7.075,10.739 8.657,9.157C10.239,7.575 11.25,5.506 11.25,3.5C11.25,3.086 11.586,2.75 12,2.75Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M19.25,1.75C19.463,1.75 19.648,1.898 19.695,2.106L19.93,3.146C20.09,3.856 20.644,4.41 21.354,4.57L22.394,4.805C22.602,4.852 22.75,5.037 22.75,5.25C22.75,5.463 22.602,5.648 22.394,5.695L21.354,5.93C20.644,6.09 20.09,6.644 19.93,7.354L19.695,8.394C19.648,8.602 19.463,8.75 19.25,8.75C19.037,8.75 18.852,8.602 18.805,8.394L18.57,7.354C18.41,6.644 17.856,6.09 17.146,5.93L16.106,5.695C15.898,5.648 15.75,5.463 15.75,5.25C15.75,5.037 15.898,4.852 16.106,4.805L17.146,4.57C17.856,4.41 18.41,3.856 18.57,3.146L18.805,2.106C18.852,1.898 19.037,1.75 19.25,1.75Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M4.75,16.25C4.963,16.25 5.148,16.398 5.195,16.606L5.43,17.646C5.59,18.356 6.144,18.91 6.854,19.07L7.894,19.305C8.102,19.352 8.25,19.537 8.25,19.75C8.25,19.963 8.102,20.148 7.894,20.195L6.854,20.43C6.144,20.59 5.59,21.144 5.43,21.854L5.195,22.894C5.148,23.102 4.963,23.25 4.75,23.25C4.537,23.25 4.352,23.102 4.305,22.894L4.07,21.854C3.91,21.144 3.356,20.59 2.646,20.43L1.606,20.195C1.398,20.148 1.25,19.963 1.25,19.75C1.25,19.537 1.398,19.352 1.606,19.305L2.646,19.07C3.356,18.91 3.91,18.356 4.07,17.646L4.305,16.606C4.352,16.398 4.537,16.25 4.75,16.25Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:strokeAlpha="0.1"
android:fillColor="#0099FF"
android:fillAlpha="0.1"/>
<path
android:pathData="M9,10L27,10A3,3 0,0 1,30 13L30,23A3,3 0,0 1,27 26L9,26A3,3 0,0 1,6 23L6,13A3,3 0,0 1,9 10z"
android:fillColor="#0099FF"/>
<path
android:pathData="M13.051,20.582H11.502L10.34,16.5C10.285,16.312 10.167,16.146 9.995,16.068C9.565,15.871 9.092,15.715 8.575,15.636V15.479H11.071C11.415,15.479 11.674,15.715 11.717,15.989L12.32,18.933L13.868,15.479H15.375L13.051,20.582ZM16.235,20.58H14.771L15.976,15.477H17.44L16.235,20.58ZM19.335,16.891C19.378,16.616 19.636,16.459 19.938,16.459C20.412,16.419 20.927,16.498 21.358,16.694L21.617,15.595C21.186,15.438 20.712,15.359 20.282,15.359C18.862,15.359 17.829,16.066 17.829,17.047C17.829,17.794 18.561,18.185 19.077,18.422C19.636,18.657 19.852,18.814 19.809,19.049C19.809,19.403 19.378,19.56 18.948,19.56C18.432,19.56 17.915,19.442 17.442,19.246L17.184,20.345C17.7,20.541 18.259,20.62 18.776,20.62C20.368,20.659 21.358,19.952 21.358,18.892C21.358,17.558 19.335,17.479 19.335,16.891ZM26.48,20.58L25.318,15.477H24.07C23.811,15.477 23.553,15.634 23.467,15.869L21.315,20.58H22.822L23.122,19.834H24.973L25.146,20.58H26.48ZM24.283,16.852L24.713,18.775H23.508L24.283,16.852Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,50 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<group>
<clip-path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"/>
</group>
<group>
<clip-path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"/>
<path
android:pathData="M0,31.5l0,-31.5l36,-0l0,31.5z"
android:fillColor="#F5F7F8"/>
<path
android:pathData="M18,9l0,-4.5l18,-0l0,4.5z"
android:fillColor="#DD2033"/>
<path
android:pathData="M18,18l0,-4.5l18,-0l0,4.5z"
android:fillColor="#DD2033"/>
<path
android:pathData="M0,27l0,-4.5l36,-0l0,4.5z"
android:fillColor="#DD2033"/>
<path
android:pathData="M0,36l0,-4.5l36,-0l0,4.5z"
android:fillColor="#DD2033"/>
<path
android:pathData="M0,18l0,-18l18,-0l0,18z"
android:fillColor="#004692"/>
<path
android:pathData="M14.2,11L13.306,13.023L11.2,13.292L12.753,14.811L12.346,17L14.2,15.75L16.054,17L15.647,14.811L17.2,13.292L15.094,13.023L14.2,11Z"
android:fillColor="#F5F7F8"/>
<path
android:pathData="M14.2,-1L13.306,1.023L11.2,1.292L12.753,2.811L12.346,5L14.2,3.75L16.054,5L15.647,2.811L17.2,1.292L15.094,1.023L14.2,-1Z"
android:fillColor="#F5F7F8"/>
<path
android:pathData="M10.2,5L9.306,7.023L7.2,7.292L8.753,8.811L8.346,11L10.2,9.75L12.054,11L11.647,8.811L13.2,7.292L11.094,7.023L10.2,5Z"
android:fillColor="#F5F7F8"/>
<path
android:pathData="M5.7,11L4.806,13.023L2.7,13.292L4.253,14.811L3.846,17L5.7,15.75L7.554,17L7.147,14.811L8.7,13.292L6.594,13.023L5.7,11Z"
android:fillColor="#F5F7F8"/>
<path
android:pathData="M5.7,-1L4.806,1.023L2.7,1.292L4.253,2.811L3.846,5L5.7,3.75L7.554,5L7.147,2.811L8.7,1.292L6.594,1.023L5.7,-1Z"
android:fillColor="#F5F7F8"/>
<path
android:pathData="M1.7,5L0.806,7.023L-1.3,7.292L0.253,8.811L-0.154,11L1.7,9.75L3.554,11L3.147,8.811L4.7,7.292L2.594,7.023L1.7,5Z"
android:fillColor="#F5F7F8"/>
</group>
</vector>

View file

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26dp"
android:height="16dp"
android:viewportWidth="26"
android:viewportHeight="16">
<path
android:pathData="M3,0L23,0A3,3 0,0 1,26 3L26,13A3,3 0,0 1,23 16L3,16A3,3 0,0 1,0 13L0,3A3,3 0,0 1,3 0z"
android:strokeAlpha="0.5"
android:fillColor="#474E71"
android:fillAlpha="0.4"/>
<path
android:pathData="M7.521,11.139H5.788L4.488,6.193C4.427,5.966 4.296,5.765 4.103,5.67C3.622,5.431 3.093,5.242 2.515,5.146V4.956H5.306C5.692,4.956 5.981,5.242 6.029,5.574L6.703,9.142L8.435,4.956H10.12L7.521,11.139ZM11.082,11.139H9.445L10.793,4.956H12.429L11.082,11.139ZM14.549,6.668C14.597,6.335 14.886,6.145 15.223,6.145C15.753,6.097 16.33,6.192 16.811,6.43L17.1,5.099C16.619,4.908 16.089,4.813 15.608,4.813C14.02,4.813 12.864,5.669 12.864,6.858C12.864,7.762 13.683,8.237 14.261,8.523C14.886,8.808 15.127,8.998 15.078,9.284C15.078,9.712 14.597,9.902 14.116,9.902C13.538,9.902 12.96,9.759 12.431,9.521L12.142,10.853C12.72,11.091 13.345,11.186 13.924,11.186C15.705,11.233 16.811,10.378 16.811,9.093C16.811,7.476 14.549,7.381 14.549,6.668ZM22.54,11.139L21.241,4.956H19.845C19.556,4.956 19.267,5.146 19.171,5.431L16.764,11.139H18.449L18.785,10.236H20.855L21.048,11.139H22.54ZM20.083,6.621L20.564,8.951H19.216L20.083,6.621Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillType="evenOdd"
android:fillAlpha="0.5"/>
</vector>