Updated on 2026-08-14
This commit is contained in:
parent
de3bdb3cb0
commit
56164d0b8b
36 changed files with 255 additions and 124 deletions
1
features/biometry/api/.gitignore
vendored
Normal file
1
features/biometry/api/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
15
features/biometry/api/build.gradle.kts
Normal file
15
features/biometry/api/build.gradle.kts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.features.biometry"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/* Project - Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.biometry
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface AskBiometryComponent : ComposableContentComponent, ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val bottomSheetVariant: Boolean,
|
||||
val modelCallbacks: ModelCallbacks,
|
||||
)
|
||||
|
||||
interface ModelCallbacks {
|
||||
fun onAllowed()
|
||||
fun onDenied()
|
||||
}
|
||||
|
||||
interface Factory : ComponentFactory<Params, AskBiometryComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.features.biometry
|
||||
|
||||
interface BiometryFeatureToggles {
|
||||
val isAskForBiometryEnabled: Boolean
|
||||
}
|
||||
1
features/biometry/impl/.gitignore
vendored
Normal file
1
features/biometry/impl/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
52
features/biometry/impl/build.gradle.kts
Normal file
52
features/biometry/impl/build.gradle.kts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.features.biometry.impl"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.features.biometry.api)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.res)
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.configToggles)
|
||||
implementation(projects.core.navigation)
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.card)
|
||||
|
||||
/** Compose libraries */
|
||||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.animation)
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(projects.libs.tangemSdkApi)
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.card.android) {
|
||||
exclude(module = "joda-time")
|
||||
}
|
||||
|
||||
/** Other */
|
||||
implementation(deps.timber)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.tangem.features.biometry.impl
|
||||
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.features.biometry.AskBiometryComponent
|
||||
import com.tangem.features.biometry.impl.model.AskBiometryModel
|
||||
import com.tangem.features.biometry.impl.ui.AskBiometry
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
internal class DefaultAskBiometryComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: AskBiometryComponent.Params,
|
||||
) : AskBiometryComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: AskBiometryModel = getOrCreateModel(params)
|
||||
private val bsShown = instanceKeeper.getOrCreateSimple { MutableStateFlow(true) }
|
||||
|
||||
init {
|
||||
model.dismissBSFlow
|
||||
.onEach { bsShown.value = false }
|
||||
.launchIn(componentScope)
|
||||
}
|
||||
|
||||
override fun dismiss() = model.dismiss()
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val bsShown by bsShown.collectAsStateWithLifecycle()
|
||||
val bsConfig = remember(this, bsShown) {
|
||||
TangemBottomSheetConfig(
|
||||
isShown = bsShown,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
}
|
||||
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = bsConfig,
|
||||
content = { AskBiometry(state) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
AskBiometry(
|
||||
modifier = modifier.navigationBarsPadding(),
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : AskBiometryComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: AskBiometryComponent.Params,
|
||||
): DefaultAskBiometryComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.features.biometry.impl
|
||||
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.features.biometry.BiometryFeatureToggles
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultBiometryFeatureToggles @Inject constructor(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) : BiometryFeatureToggles {
|
||||
override val isAskForBiometryEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled("ASK_BIOMETRY_REFACTORING_ENABLED")
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.features.biometry.impl.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.biometry.AskBiometryComponent
|
||||
import com.tangem.features.biometry.BiometryFeatureToggles
|
||||
import com.tangem.features.biometry.impl.DefaultAskBiometryComponent
|
||||
import com.tangem.features.biometry.impl.DefaultBiometryFeatureToggles
|
||||
import com.tangem.features.biometry.impl.model.AskBiometryModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface FeatureModule {
|
||||
|
||||
@Binds
|
||||
fun bindFeatureToggles(impl: DefaultBiometryFeatureToggles): BiometryFeatureToggles
|
||||
|
||||
@Binds
|
||||
fun bindComponentFactory(impl: DefaultAskBiometryComponent.Factory): AskBiometryComponent.Factory
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface ModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AskBiometryModel::class)
|
||||
fun provideModel(model: AskBiometryModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
package com.tangem.features.biometry.impl.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.settings.SettingsManager
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.settings.SetSaveWalletScreenShownUseCase
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.biometry.AskBiometryComponent
|
||||
import com.tangem.features.biometry.impl.ui.state.AskBiometryUM
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class AskBiometryModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
paramsContainer: ParamsContainer,
|
||||
private val setSaveWalletScreenShownUseCase: SetSaveWalletScreenShownUseCase,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
private val settingsManager: SettingsManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<AskBiometryComponent.Params>()
|
||||
|
||||
private val _uiState = MutableStateFlow(
|
||||
AskBiometryUM(
|
||||
bottomSheetVariant = params.bottomSheetVariant,
|
||||
onAllowClick = ::onAllowClick,
|
||||
onDontAllowClick = ::dontAllow,
|
||||
onDismiss = ::dismiss,
|
||||
),
|
||||
)
|
||||
val uiState = _uiState.asStateFlow()
|
||||
val dismissBSFlow = MutableSharedFlow<Unit>()
|
||||
|
||||
init {
|
||||
modelScope.launch {
|
||||
setSaveWalletScreenShownUseCase()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAllowClick() {
|
||||
_uiState.update { it.copy(showProgress = true) }
|
||||
allowToUseBiometrics()
|
||||
}
|
||||
|
||||
private fun dontAllow() {
|
||||
params.modelCallbacks.onDenied()
|
||||
}
|
||||
|
||||
fun dismiss() {
|
||||
modelScope.launch {
|
||||
dismissBSFlow.emit(Unit)
|
||||
delay(timeMillis = 500)
|
||||
dontAllow()
|
||||
}
|
||||
}
|
||||
|
||||
private fun allowToUseBiometrics() {
|
||||
modelScope.launch {
|
||||
if (tangemSdkManager.checkNeedEnrollBiometrics()) {
|
||||
showEnrollBiometricsDialog()
|
||||
return@launch
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
* because it will be automatically saved on UserWalletsListManager switch
|
||||
*/
|
||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync ?: run {
|
||||
Timber.e("Unable to save user wallet")
|
||||
uiMessageSender.send(
|
||||
SnackbarMessage(stringReference("No selected user wallet")),
|
||||
)
|
||||
|
||||
return@launch
|
||||
}
|
||||
|
||||
handleSuccessAllowing(selectedUserWallet)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleSuccessAllowing(userWallet: UserWallet) {
|
||||
walletsRepository.saveShouldSaveUserWallets(item = true)
|
||||
settingsRepository.setShouldSaveAccessCodes(value = true)
|
||||
|
||||
cardSdkConfigRepository.setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = userWallet.hasAccessCode,
|
||||
)
|
||||
|
||||
if (_uiState.value.bottomSheetVariant) {
|
||||
dismissBSFlow.emit(Unit)
|
||||
delay(timeMillis = 500)
|
||||
}
|
||||
|
||||
params.modelCallbacks.onAllowed()
|
||||
}
|
||||
|
||||
private fun showEnrollBiometricsDialog() {
|
||||
uiMessageSender.send(
|
||||
DialogMessage(
|
||||
message = resourceReference(R.string.save_user_wallet_agreement_enroll_biometrics_description),
|
||||
title = resourceReference(R.string.save_user_wallet_agreement_enroll_biometrics_title),
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(R.string.common_enable),
|
||||
onClick = { settingsManager.openBiometricSettings() },
|
||||
),
|
||||
secondAction = EventMessageAction(
|
||||
title = resourceReference(R.string.common_cancel),
|
||||
onClick = {},
|
||||
),
|
||||
dismissOnFirstAction = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
package com.tangem.features.biometry.impl.ui
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.biometry.impl.ui.state.AskBiometryUM
|
||||
import com.tangem.features.biometry.R
|
||||
|
||||
@Composable
|
||||
internal fun AskBiometry(state: AskBiometryUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
if (state.bottomSheetVariant) {
|
||||
Header(onCloseClick = state.onDismiss)
|
||||
}
|
||||
|
||||
SpacerH32()
|
||||
SpacerHHalf()
|
||||
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Title(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing56))
|
||||
SpacerH32()
|
||||
Description(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing34)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
||||
SpacerHHalf()
|
||||
}
|
||||
Footer(state = state)
|
||||
SpacerH16()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Header(onCloseClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size32),
|
||||
onClick = onCloseClick,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = R.drawable.ic_close_24),
|
||||
tint = TangemTheme.colors.icon.secondary,
|
||||
contentDescription = stringResourceSafe(id = R.string.common_cancel),
|
||||
)
|
||||
}
|
||||
SpacerW8()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Title(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing32),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size56),
|
||||
painter = painterResource(id = R.drawable.ic_fingerprint_24),
|
||||
tint = TangemTheme.colors.icon.primary1,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_header_biometrics),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Description(modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
DescriptionItem(
|
||||
iconPainter = painterResource(id = R.drawable.ic_face_recognition_24),
|
||||
title = stringResourceSafe(id = R.string.save_user_wallet_agreement_access_title),
|
||||
description = stringResourceSafe(id = R.string.save_user_wallet_agreement_access_description),
|
||||
)
|
||||
DescriptionItem(
|
||||
iconPainter = painterResource(id = R.drawable.ic_lock_24),
|
||||
title = stringResourceSafe(id = R.string.save_user_wallet_agreement_code_title),
|
||||
description = stringResourceSafe(id = R.string.save_user_wallet_agreement_code_description_biometrics),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Footer(state: AskBiometryUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
PrimaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
showProgress = state.showProgress,
|
||||
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_allow_biometrics),
|
||||
onClick = state.onAllowClick,
|
||||
)
|
||||
|
||||
if (state.bottomSheetVariant.not()) {
|
||||
SpacerH12()
|
||||
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_dont_allow),
|
||||
onClick = state.onDontAllowClick,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH16()
|
||||
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(fraction = .7f),
|
||||
text = stringResourceSafe(R.string.save_user_wallet_agreement_notice),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DescriptionItem(iconPainter: Painter, title: String, description: String) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Top,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = iconPainter,
|
||||
tint = TangemTheme.colors.icon.primary1,
|
||||
contentDescription = null,
|
||||
)
|
||||
SpacerW24()
|
||||
Column {
|
||||
Text(
|
||||
text = title,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
SpacerH4()
|
||||
Text(
|
||||
text = description,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
TangemThemePreview {
|
||||
AskBiometry(
|
||||
state = AskBiometryUM(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun PreviewBS() {
|
||||
TangemThemePreview {
|
||||
AskBiometry(
|
||||
state = AskBiometryUM(bottomSheetVariant = true),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.features.biometry.impl.ui.state
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class AskBiometryUM(
|
||||
val bottomSheetVariant: Boolean = false,
|
||||
val showProgress: Boolean = false,
|
||||
val error: TextReference? = null,
|
||||
val onAllowClick: () -> Unit = {},
|
||||
val onDontAllowClick: () -> Unit = {},
|
||||
val onDismiss: () -> Unit = {},
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue