Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-14 17:18:57 +03:00
commit 79c581b209
8 changed files with 294 additions and 0 deletions

View file

@ -0,0 +1,143 @@
package com.tangem.core.ui.components.showcase
import android.content.res.Configuration
import androidx.annotation.DrawableRes
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SecondaryButton
import com.tangem.core.ui.components.showcase.model.ShowcaseButtonModel
import com.tangem.core.ui.components.showcase.model.ShowcaseItemModel
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
/**
* @param headerIconRes big header icon
* @param headerText header text
* @param showcaseItems list of bullet points
* @param primaryButton primary button
* @param secondaryButton secondary button
* @param modifier compose modifier
*
* @see <a href = "https://www.figma.com/design/Vs6SkVsFnUPsSCNwlnVf5U/Android-%E2%80%93-UI?node-id=12620-90568&t=WeCOVTgeYfkr24Ff-4"
* >Figma component</a>
*/
@Composable
fun Showcase(
@DrawableRes headerIconRes: Int,
headerText: TextReference,
showcaseItems: ImmutableList<ShowcaseItemModel>,
primaryButton: ShowcaseButtonModel,
secondaryButton: ShowcaseButtonModel,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier.fillMaxSize(),
) {
ShowcaseContent(
headerIconRes = headerIconRes,
headerText = headerText,
showcaseItems = showcaseItems,
modifier = Modifier
.weight(1f)
.align(Alignment.CenterHorizontally),
)
ShowcaseButtons(
primaryButtonText = primaryButton.buttonText,
onPrimaryClick = primaryButton.onClick,
secondaryButtonText = secondaryButton.buttonText,
onSecondaryClick = secondaryButton.onClick,
)
}
}
@Composable
private fun ShowcaseButtons(
primaryButtonText: TextReference,
secondaryButtonText: TextReference,
onPrimaryClick: () -> Unit,
onSecondaryClick: () -> Unit,
hint: TextReference? = null,
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
PrimaryButton(
text = primaryButtonText.resolveReference(),
onClick = onPrimaryClick,
modifier = Modifier
.fillMaxWidth()
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
),
)
SecondaryButton(
text = secondaryButtonText.resolveReference(),
onClick = onSecondaryClick,
modifier = Modifier
.fillMaxWidth()
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
top = TangemTheme.dimens.spacing12,
bottom = TangemTheme.dimens.spacing16,
),
)
hint?.let {
Text(
text = it.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier
.fillMaxWidth()
.padding(
start = TangemTheme.dimens.spacing16,
end = TangemTheme.dimens.spacing16,
bottom = TangemTheme.dimens.spacing12,
),
)
}
}
}
// region Preview
@Preview(showBackground = true, widthDp = 360, heightDp = 720)
@Preview(showBackground = true, widthDp = 360, heightDp = 720, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Showcase_Preview() {
TangemThemePreview {
Showcase(
headerIconRes = R.drawable.ic_notifications_unread_24,
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),
),
ShowcaseItemModel(
R.drawable.ic_storefront_24,
resourceReference(R.string.user_push_notification_agreement_argument_two),
),
),
primaryButton = ShowcaseButtonModel(resourceReference(R.string.common_allow), {}),
secondaryButton = ShowcaseButtonModel(resourceReference(R.string.common_later), {}),
modifier = Modifier.background(TangemTheme.colors.background.primary),
)
}
}
// endregion

View file

@ -0,0 +1,71 @@
package com.tangem.core.ui.components.showcase
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
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.text.style.TextAlign
import com.tangem.core.ui.components.showcase.model.ShowcaseItemModel
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import kotlinx.collections.immutable.ImmutableList
@Composable
fun ShowcaseContent(
@DrawableRes headerIconRes: Int,
headerText: TextReference,
showcaseItems: ImmutableList<ShowcaseItemModel>,
modifier: Modifier = Modifier,
) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier,
) {
Icon(
painter = painterResource(id = headerIconRes),
contentDescription = null,
tint = TangemTheme.colors.icon.primary1,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.size(TangemTheme.dimens.size56),
)
Text(
text = headerText.resolveReference(),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(
start = TangemTheme.dimens.spacing34,
end = TangemTheme.dimens.spacing34,
top = TangemTheme.dimens.spacing28,
),
)
Column(
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing34,
end = TangemTheme.dimens.spacing34,
top = TangemTheme.dimens.spacing28,
),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
horizontalAlignment = Alignment.CenterHorizontally,
) {
repeat(showcaseItems.size) { index ->
ShowcaseItem(
iconRes = showcaseItems[index].iconRes,
text = showcaseItems[index].text,
)
}
}
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.core.ui.components.showcase
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
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 {
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,
modifier = Modifier.padding(start = TangemTheme.dimens.spacing20),
)
}
}

View file

@ -0,0 +1,8 @@
package com.tangem.core.ui.components.showcase.model
import com.tangem.core.ui.extensions.TextReference
data class ShowcaseButtonModel(
val buttonText: TextReference,
val onClick: () -> Unit,
)

View file

@ -0,0 +1,9 @@
package com.tangem.core.ui.components.showcase.model
import androidx.annotation.DrawableRes
import com.tangem.core.ui.extensions.TextReference
data class ShowcaseItemModel(
@DrawableRes val iconRes: Int,
val text: TextReference,
)

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<group>
<clip-path android:pathData="M0,0h24v24h-24z"/>
<path android:fillColor="#1E1E1E" android:pathData="M11.998,21.692C11.501,21.692 11.075,21.515 10.722,21.161C10.369,20.807 10.192,20.382 10.192,19.885H13.808C13.808,20.383 13.631,20.809 13.276,21.163C12.922,21.516 12.496,21.692 11.998,21.692ZM4.5,18.885V17.385H6.308V9.923C6.308,8.578 6.723,7.389 7.553,6.356C8.383,5.322 9.449,4.661 10.75,4.373V3.75C10.75,3.403 10.871,3.108 11.114,2.865C11.357,2.622 11.652,2.5 11.999,2.5C12.346,2.5 12.641,2.622 12.884,2.865C13.128,3.108 13.25,3.403 13.25,3.75V3.95C13.086,4.246 12.956,4.547 12.859,4.854C12.763,5.16 12.704,5.478 12.683,5.808C12.569,5.787 12.458,5.769 12.35,5.754C12.242,5.738 12.125,5.731 12,5.731C10.842,5.731 9.854,6.14 9.035,6.959C8.217,7.777 7.808,8.765 7.808,9.923V17.385H16.192V11.133C16.422,11.215 16.664,11.279 16.919,11.325C17.174,11.371 17.432,11.391 17.692,11.385V17.385H19.5V18.885H4.5ZM17.482,9.202C16.718,9.202 16.069,8.935 15.534,8.4C14.998,7.866 14.731,7.217 14.731,6.453C14.731,5.689 14.998,5.04 15.533,4.505C16.067,3.97 16.716,3.702 17.479,3.702C18.243,3.702 18.893,3.969 19.428,4.504C19.963,5.038 20.231,5.687 20.231,6.451C20.231,7.214 19.963,7.864 19.429,8.399C18.895,8.934 18.245,9.202 17.482,9.202Z"/>
</group>
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<group>
<clip-path android:pathData="M0,0h24v24h-24z"/>
<path android:fillColor="#1E1E1E" android:pathData="M5.65,10.025L7.6,10.85C7.833,10.383 8.075,9.933 8.325,9.5C8.575,9.067 8.85,8.633 9.15,8.2L7.75,7.925L5.65,10.025ZM9.2,12.1L12.05,14.925C12.75,14.658 13.5,14.25 14.3,13.7C15.1,13.15 15.85,12.525 16.55,11.825C17.717,10.658 18.629,9.363 19.288,7.938C19.946,6.512 20.233,5.2 20.15,4C18.95,3.917 17.633,4.204 16.2,4.863C14.767,5.521 13.467,6.433 12.3,7.6C11.6,8.3 10.975,9.05 10.425,9.85C9.875,10.65 9.467,11.4 9.2,12.1ZM13.65,10.475C13.267,10.092 13.075,9.621 13.075,9.063C13.075,8.504 13.267,8.033 13.65,7.65C14.033,7.267 14.508,7.075 15.075,7.075C15.642,7.075 16.117,7.267 16.5,7.65C16.883,8.033 17.075,8.504 17.075,9.063C17.075,9.621 16.883,10.092 16.5,10.475C16.117,10.858 15.642,11.05 15.075,11.05C14.508,11.05 14.033,10.858 13.65,10.475ZM14.125,18.5L16.225,16.4L15.95,15C15.517,15.3 15.083,15.571 14.65,15.813C14.217,16.054 13.767,16.292 13.3,16.525L14.125,18.5ZM21.95,2.175C22.267,4.192 22.071,6.154 21.362,8.063C20.654,9.971 19.433,11.792 17.7,13.525L18.2,16C18.267,16.333 18.25,16.658 18.15,16.975C18.05,17.292 17.883,17.567 17.65,17.8L13.45,22L11.35,17.075L7.075,12.8L2.15,10.7L6.325,6.5C6.558,6.267 6.837,6.1 7.162,6C7.487,5.9 7.817,5.883 8.15,5.95L10.625,6.45C12.358,4.717 14.175,3.492 16.075,2.775C17.975,2.058 19.933,1.858 21.95,2.175ZM3.925,15.975C4.508,15.392 5.221,15.096 6.062,15.087C6.904,15.079 7.617,15.367 8.2,15.95C8.783,16.533 9.071,17.246 9.062,18.087C9.054,18.929 8.758,19.642 8.175,20.225C7.758,20.642 7.062,21 6.087,21.3C5.112,21.6 3.767,21.867 2.05,22.1C2.283,20.383 2.55,19.038 2.85,18.063C3.15,17.087 3.508,16.392 3.925,15.975ZM5.35,17.375C5.183,17.542 5.017,17.846 4.85,18.288C4.683,18.729 4.567,19.175 4.5,19.625C4.95,19.558 5.396,19.446 5.837,19.288C6.279,19.129 6.583,18.967 6.75,18.8C6.95,18.6 7.058,18.358 7.075,18.075C7.092,17.792 7,17.55 6.8,17.35C6.6,17.15 6.358,17.054 6.075,17.063C5.792,17.071 5.55,17.175 5.35,17.375Z"/>
</group>
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<group>
<clip-path android:pathData="M0,0h24v24h-24z"/>
<path android:fillColor="#1E1E1E" android:pathData="M21.025,11.05V19C21.025,19.55 20.829,20.021 20.438,20.413C20.046,20.804 19.575,21 19.025,21H5.025C4.475,21 4.004,20.804 3.612,20.413C3.221,20.021 3.025,19.55 3.025,19V11.05C2.642,10.7 2.346,10.25 2.137,9.7C1.929,9.15 1.925,8.55 2.125,7.9L3.175,4.5C3.308,4.067 3.546,3.708 3.887,3.425C4.229,3.142 4.625,3 5.075,3H18.975C19.425,3 19.817,3.138 20.15,3.412C20.483,3.688 20.725,4.05 20.875,4.5L21.925,7.9C22.125,8.55 22.121,9.142 21.913,9.675C21.704,10.208 21.408,10.667 21.025,11.05ZM14.225,10C14.675,10 15.017,9.846 15.25,9.538C15.483,9.229 15.575,8.883 15.525,8.5L14.975,5H13.025V8.7C13.025,9.05 13.142,9.354 13.375,9.613C13.608,9.871 13.892,10 14.225,10ZM9.725,10C10.108,10 10.421,9.871 10.663,9.613C10.904,9.354 11.025,9.05 11.025,8.7V5H9.075L8.525,8.5C8.458,8.9 8.546,9.25 8.787,9.55C9.029,9.85 9.342,10 9.725,10ZM5.275,10C5.575,10 5.837,9.892 6.062,9.675C6.287,9.458 6.425,9.183 6.475,8.85L7.025,5H5.075L4.075,8.35C3.975,8.683 4.029,9.042 4.237,9.425C4.446,9.808 4.792,10 5.275,10ZM18.775,10C19.258,10 19.608,9.808 19.825,9.425C20.042,9.042 20.092,8.683 19.975,8.35L18.925,5H17.025L17.575,8.85C17.625,9.183 17.763,9.458 17.987,9.675C18.212,9.892 18.475,10 18.775,10ZM5.025,19H19.025V11.95C18.942,11.983 18.888,12 18.862,12H18.775C18.325,12 17.929,11.925 17.587,11.775C17.246,11.625 16.908,11.383 16.575,11.05C16.275,11.35 15.933,11.583 15.55,11.75C15.167,11.917 14.758,12 14.325,12C13.875,12 13.454,11.917 13.063,11.75C12.671,11.583 12.325,11.35 12.025,11.05C11.742,11.35 11.413,11.583 11.038,11.75C10.663,11.917 10.258,12 9.825,12C9.342,12 8.904,11.917 8.512,11.75C8.121,11.583 7.775,11.35 7.475,11.05C7.125,11.4 6.779,11.646 6.437,11.788C6.096,11.929 5.708,12 5.275,12H5.162C5.121,12 5.075,11.983 5.025,11.95V19Z"/>
</group>
</vector>