Updated on 2026-08-14
This commit is contained in:
parent
bd411ae949
commit
49127d64dd
9 changed files with 603 additions and 0 deletions
|
|
@ -1612,6 +1612,7 @@
|
|||
<string name="tangempay_card_details_withdraw_error_title">Withdraw unavailable now</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_description">You can\'t initiate swap or new withdrawal till the current one is finished</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_title">Withdrawal in progress</string>
|
||||
<string name="tangempay_card_page_settings_title">Card settings</string>
|
||||
<string name="tangempay_change_pin_code">Change PIN-code</string>
|
||||
<string name="tangempay_come_back_if_forget_pin">Come back to the app if you forget it.</string>
|
||||
<string name="tangempay_factory_settings_warning_title">I understand that I will completely lose access to my Tangem Pay Card and all funds on it without the possibility of recovery</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.tangempay.components
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
|
||||
interface TangemPayCardPageComponent : ComposableContentComponent {
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val config: TangemPayDetailsConfig,
|
||||
)
|
||||
interface Factory : ComponentFactory<Params, TangemPayCardPageComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package com.tangem.features.tangempay.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultTangemPayCardPageComponent @AssistedInject constructor(
|
||||
@Assisted private val appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: TangemPayCardPageComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, TangemPayCardPageComponent {
|
||||
|
||||
private val stackNavigation = StackNavigation<TangemPayDetailsInnerRoute>()
|
||||
|
||||
private val innerRouter = InnerRouter<TangemPayDetailsInnerRoute>(
|
||||
stackNavigation = stackNavigation,
|
||||
popCallback = { onChildBack() },
|
||||
)
|
||||
|
||||
private val childStack = childStack(
|
||||
key = "tangemPayCardPageInnerStack",
|
||||
source = stackNavigation,
|
||||
serializer = TangemPayDetailsInnerRoute.serializer(),
|
||||
initialConfiguration = TangemPayDetailsInnerRoute.Details,
|
||||
childFactory = ::screenChild,
|
||||
)
|
||||
|
||||
@Suppress("ReusedModifierInstance")
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val childStack by childStack.subscribeAsState()
|
||||
Children(
|
||||
stack = childStack,
|
||||
animation = stackAnimation(),
|
||||
) { child ->
|
||||
child.instance.Content(modifier = modifier)
|
||||
}
|
||||
}
|
||||
|
||||
private fun screenChild(
|
||||
config: TangemPayDetailsInnerRoute,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableContentComponent = when (config) {
|
||||
TangemPayDetailsInnerRoute.Details -> TangemPayCardPageScreenComponent(
|
||||
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||
params = params,
|
||||
)
|
||||
TangemPayDetailsInnerRoute.ChangePIN -> TangemPayChangePinComponent(
|
||||
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||
params = TangemPayDetailsContainerComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
config = params.config,
|
||||
),
|
||||
)
|
||||
TangemPayDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
|
||||
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||
)
|
||||
TangemPayDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
|
||||
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||
params = TangemPayDetailsContainerComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
config = params.config,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onChildBack() {
|
||||
if (childStack.value.backStack.isEmpty()) {
|
||||
router.pop()
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : TangemPayCardPageComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: TangemPayCardPageComponent.Params,
|
||||
): DefaultTangemPayCardPageComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.features.tangempay.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.DefaultTangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
||||
import com.tangem.features.tangempay.model.TangemPayCardPageModel
|
||||
import com.tangem.features.tangempay.ui.TangemPayCardPageScreen
|
||||
|
||||
internal class TangemPayCardPageScreenComponent(
|
||||
private val appComponentContext: AppComponentContext,
|
||||
private val params: TangemPayCardPageComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, ComposableContentComponent {
|
||||
|
||||
private val model: TangemPayCardPageModel = getOrCreateModel(params = params)
|
||||
|
||||
private val containerParams = TangemPayDetailsContainerComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
config = params.config,
|
||||
)
|
||||
|
||||
private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent(
|
||||
appComponentContext = child("cardDetailsBlockComponent"),
|
||||
params = TangemPayCardDetailsBlockComponent.Params(params = containerParams),
|
||||
)
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = TangemPayDetailsNavigation.serializer(),
|
||||
handleBackButton = false,
|
||||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val cardDetailsState by cardDetailsBlockComponent.state.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
|
||||
NavigationBar3ButtonsScrim()
|
||||
TangemPayCardPageScreen(
|
||||
state = state,
|
||||
cardDetailsBlockComponent = cardDetailsBlockComponent,
|
||||
cardDetailsState = cardDetailsState,
|
||||
modifier = modifier,
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(
|
||||
navigation: TangemPayDetailsNavigation,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent {
|
||||
val context = childByContext(componentContext)
|
||||
return when (navigation) {
|
||||
is TangemPayDetailsNavigation.ViewPinCode -> TangemPayViewPinComponent(
|
||||
appComponentContext = context,
|
||||
params = TangemPayViewPinComponent.Params(
|
||||
walletId = navigation.userWalletId,
|
||||
cardId = navigation.cardId,
|
||||
listener = model,
|
||||
),
|
||||
)
|
||||
else -> error("Unsupported bottom sheet navigation: $navigation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.features.tangempay.di
|
||||
|
||||
import com.tangem.features.tangempay.components.DefaultTangemPayCardPageComponent
|
||||
import com.tangem.features.tangempay.components.DefaultTangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayCardPageComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
|
||||
import com.tangem.features.tangempay.model.listener.DefaultCardDetailsEventListener
|
||||
|
|
@ -20,6 +22,12 @@ internal interface TangemPayDetailsFeatureModule {
|
|||
factory: DefaultTangemPayDetailsContainerComponent.Factory,
|
||||
): TangemPayDetailsContainerComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPayCardPageComponentFactory(
|
||||
factory: DefaultTangemPayCardPageComponent.Factory,
|
||||
): TangemPayCardPageComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindCardDetailsEventListener(impl: DefaultCardDetailsEventListener): CardDetailsEventListener
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.features.tangempay.model.TangemPayAddFundsModel
|
||||
import com.tangem.features.tangempay.model.TangemPayAddToWalletModel
|
||||
import com.tangem.features.tangempay.model.TangemPayCardDetailsBlockModel
|
||||
import com.tangem.features.tangempay.model.TangemPayCardPageModel
|
||||
import com.tangem.features.tangempay.model.TangemPayChangePinModel
|
||||
import com.tangem.features.tangempay.model.TangemPayDetailsModel
|
||||
import com.tangem.features.tangempay.model.TangemPayTxHistoryDetailsModel
|
||||
|
|
@ -59,4 +60,9 @@ internal interface TangemPayModelModule {
|
|||
@IntoMap
|
||||
@ClassKey(TangemPayViewPinModel::class)
|
||||
fun bindTangemPayViewPinModel(model: TangemPayViewPinModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TangemPayCardPageModel::class)
|
||||
fun bindTangemPayCardPageModel(model: TangemPayCardPageModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.features.tangempay.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Immutable
|
||||
internal data class TangemPayCardPageUM(
|
||||
val addToWalletBlockState: AddToWalletBlockState? = null,
|
||||
val settings: ImmutableList<TangemPayCardPageSetting> = persistentListOf(
|
||||
TangemPayCardPageSetting.ChangePIN,
|
||||
TangemPayCardPageSetting.FreezeCard,
|
||||
),
|
||||
val onBackClick: () -> Unit,
|
||||
val onSettingClick: (TangemPayCardPageSetting) -> Unit,
|
||||
) {
|
||||
companion object {
|
||||
fun stub(
|
||||
addToWalletBlockState: AddToWalletBlockState? = AddToWalletBlockState(onClick = {}, onClickClose = {}),
|
||||
settings: ImmutableList<TangemPayCardPageSetting> = persistentListOf(
|
||||
TangemPayCardPageSetting.ChangePIN,
|
||||
TangemPayCardPageSetting.FreezeCard,
|
||||
TangemPayCardPageSetting.ReplaceCard,
|
||||
),
|
||||
) = TangemPayCardPageUM(
|
||||
addToWalletBlockState = addToWalletBlockState,
|
||||
settings = settings,
|
||||
onBackClick = {},
|
||||
onSettingClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed class TangemPayCardPageSetting {
|
||||
data object ChangePIN : TangemPayCardPageSetting()
|
||||
data object FreezeCard : TangemPayCardPageSetting()
|
||||
data object ReplaceCard : TangemPayCardPageSetting()
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
package com.tangem.features.tangempay.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
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.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.features.tangempay.components.TangemPayCardPageComponent
|
||||
import com.tangem.features.tangempay.components.ViewPinListener
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.AddToWalletBlockState
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardPageSetting
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardPageUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
||||
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
|
||||
import com.tangem.features.tangempay.utils.TangemPayMessagesFactory
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class TangemPayCardPageModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : Model(), ViewPinListener {
|
||||
|
||||
private val params: TangemPayCardPageComponent.Params = paramsContainer.require()
|
||||
|
||||
private var currentFrozenState: TangemPayCardFrozenState = params.config.cardFrozenState
|
||||
|
||||
private val addToWalletBannerJobHolder = JobHolder()
|
||||
|
||||
val uiState: StateFlow<TangemPayCardPageUM>
|
||||
field = MutableStateFlow(
|
||||
TangemPayCardPageUM(
|
||||
onBackClick = router::pop,
|
||||
onSettingClick = ::onSettingClick,
|
||||
),
|
||||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
||||
|
||||
init {
|
||||
fetchAddToWalletBanner()
|
||||
subscribeToCardFrozenState()
|
||||
}
|
||||
|
||||
private fun onSettingClick(setting: TangemPayCardPageSetting) = when (setting) {
|
||||
TangemPayCardPageSetting.ChangePIN -> onClickChangePIN()
|
||||
TangemPayCardPageSetting.FreezeCard -> onClickFreezeOrUnfreezeCard()
|
||||
TangemPayCardPageSetting.ReplaceCard -> Unit // TODO v_rodionov #[REDACTED_TASK_KEY]
|
||||
}
|
||||
|
||||
private fun onClickChangePIN() {
|
||||
if (!params.config.isPinSet) {
|
||||
router.push(TangemPayDetailsInnerRoute.ChangePIN)
|
||||
} else {
|
||||
bottomSheetNavigation.activate(
|
||||
TangemPayDetailsNavigation.ViewPinCode(
|
||||
userWalletId = params.userWalletId,
|
||||
cardId = params.config.cardId,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onClickFreezeOrUnfreezeCard() {
|
||||
when (currentFrozenState) {
|
||||
TangemPayCardFrozenState.Frozen -> uiMessageSender.send(
|
||||
TangemPayMessagesFactory.createUnfreezeCardMessage(onUnfreezeClicked = ::unfreezeCard),
|
||||
)
|
||||
else -> uiMessageSender.send(
|
||||
TangemPayMessagesFactory.createFreezeCardMessage(onFreezeClicked = ::freezeCard),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun freezeCard() {
|
||||
modelScope.launch {
|
||||
cardDetailsRepository.freezeCard(
|
||||
userWalletId = params.userWalletId,
|
||||
cardId = params.config.cardId,
|
||||
).onLeft {
|
||||
val message = SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed))
|
||||
uiMessageSender.send(message)
|
||||
}.onRight { state ->
|
||||
val message = if (state == TangemPayCardFrozenState.Frozen) {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_success))
|
||||
} else {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed))
|
||||
}
|
||||
uiMessageSender.send(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfreezeCard() {
|
||||
modelScope.launch {
|
||||
cardDetailsRepository.unfreezeCard(
|
||||
userWalletId = params.userWalletId,
|
||||
cardId = params.config.cardId,
|
||||
).onLeft {
|
||||
val message = SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed))
|
||||
uiMessageSender.send(message)
|
||||
}.onRight { state ->
|
||||
val message = if (state == TangemPayCardFrozenState.Unfrozen) {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_success))
|
||||
} else {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed))
|
||||
}
|
||||
uiMessageSender.send(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToCardFrozenState() {
|
||||
cardDetailsRepository
|
||||
.cardFrozenState(params.config.cardId)
|
||||
.onEach { state -> currentFrozenState = state }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun fetchAddToWalletBanner() {
|
||||
modelScope.launch {
|
||||
val isDone = cardDetailsRepository.isAddToWalletDone(params.userWalletId).getOrNull() == true
|
||||
if (!isDone) {
|
||||
uiState.update { state ->
|
||||
state.copy(
|
||||
addToWalletBlockState = AddToWalletBlockState(
|
||||
onClick = ::onClickAddToWallet,
|
||||
onClickClose = ::onClickCloseBanner,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}.saveIn(addToWalletBannerJobHolder)
|
||||
}
|
||||
|
||||
private fun onClickAddToWallet() {
|
||||
router.push(TangemPayDetailsInnerRoute.AddToWallet)
|
||||
}
|
||||
|
||||
private fun onClickCloseBanner() {
|
||||
modelScope.launch {
|
||||
cardDetailsRepository.setAddToWalletAsDone(params.userWalletId)
|
||||
uiState.update { it.copy(addToWalletBlockState = null) }
|
||||
}.saveIn(addToWalletBannerJobHolder)
|
||||
}
|
||||
|
||||
override fun onClickChangePin() {
|
||||
bottomSheetNavigation.dismiss()
|
||||
router.push(TangemPayDetailsInnerRoute.ChangePIN)
|
||||
}
|
||||
|
||||
override fun onDismissViewPin() {
|
||||
bottomSheetNavigation.dismiss()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
package com.tangem.features.tangempay.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.exclude
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardPageSetting
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardPageUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCardPageScreen(
|
||||
state: TangemPayCardPageUM,
|
||||
cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent,
|
||||
cardDetailsState: TangemPayCardDetailsUM,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
onBackClick = state.onBackClick,
|
||||
)
|
||||
},
|
||||
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(WindowInsets.navigationBars),
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) { scaffoldPaddings ->
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(scaffoldPaddings),
|
||||
contentPadding = PaddingValues(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
|
||||
),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
item(key = "Card") {
|
||||
cardDetailsBlockComponent.CardDetailsBlockContent(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8),
|
||||
state = cardDetailsState,
|
||||
)
|
||||
}
|
||||
if (state.addToWalletBlockState != null) {
|
||||
item(key = "GooglePay") {
|
||||
TangemPayAddToWalletBlock(
|
||||
state = state.addToWalletBlockState,
|
||||
)
|
||||
}
|
||||
}
|
||||
item(key = "Settings") {
|
||||
TangemPayCardPageSettingsBlock(
|
||||
settings = state.settings,
|
||||
onSettingClick = state.onSettingClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemPayCardPageSettingsBlock(
|
||||
settings: ImmutableList<TangemPayCardPageSetting>,
|
||||
onSettingClick: (TangemPayCardPageSetting) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = TangemTheme.shapes.roundedCornersMedium,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing4,
|
||||
),
|
||||
text = stringResourceSafe(R.string.tangempay_card_page_settings_title),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
settings.fastForEach { item ->
|
||||
TangemPayCardPageSettingRow(
|
||||
item = item,
|
||||
onClick = { onSettingClick(item) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemPayCardPageSettingRow(
|
||||
item: TangemPayCardPageSetting,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(TangemTheme.dimens.spacing12),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(item.titleRes),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val TangemPayCardPageSetting.titleRes
|
||||
get() = when (this) {
|
||||
TangemPayCardPageSetting.ChangePIN -> R.string.tangempay_card_details_change_pin
|
||||
TangemPayCardPageSetting.FreezeCard -> R.string.tangempay_card_details_freeze_card
|
||||
TangemPayCardPageSetting.ReplaceCard -> R.string.common_error // TODO v_rodionov #[REDACTED_TASK_KEY]
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun preview() = TangemThemePreview {
|
||||
TangemPayCardPageScreen(
|
||||
state = TangemPayCardPageUM.stub(),
|
||||
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
|
||||
TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = { _, _ -> },
|
||||
onClick = {},
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
),
|
||||
),
|
||||
cardDetailsState = TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = { _, _ -> },
|
||||
onClick = {},
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
),
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue