Updated on 2026-08-14
This commit is contained in:
parent
819ab8c161
commit
ddba5fe3cf
19 changed files with 919 additions and 68 deletions
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.features.tangempay.cashback.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
|
||||
internal class CashbackBottomSheetComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
private val onDismiss: () -> Unit,
|
||||
private val content: @Composable () -> Unit,
|
||||
) : ComposableBottomSheetComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
override fun dismiss() {
|
||||
onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
|
@ -4,10 +4,19 @@ 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.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.features.tangempay.cashback.api.TangemPayCashbackComponent
|
||||
import com.tangem.features.tangempay.cashback.impl.model.TangemPayCashbackModel
|
||||
import com.tangem.features.tangempay.cashback.impl.model.TangemPayCashbackNavigation
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.TangemPayCashbackAccrualsBottomSheet
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.TangemPayCashbackDetailsBottomSheet
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.TangemPayCashbackScreen
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -20,10 +29,50 @@ internal class DefaultTangemPayCashbackComponent @AssistedInject constructor(
|
|||
|
||||
private val model: TangemPayCashbackModel = getOrCreateModel(params)
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = TangemPayCashbackNavigation.serializer(),
|
||||
handleBackButton = false,
|
||||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
TangemPayCashbackScreen(state = state, modifier = modifier)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(
|
||||
navigation: TangemPayCashbackNavigation,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent {
|
||||
val context = childByContext(componentContext)
|
||||
return when (navigation) {
|
||||
TangemPayCashbackNavigation.Details -> CashbackBottomSheetComponent(
|
||||
appComponentContext = context,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
content = {
|
||||
val state by model.detailsSheet.collectAsStateWithLifecycle()
|
||||
TangemPayCashbackDetailsBottomSheet(
|
||||
state = state,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
)
|
||||
},
|
||||
)
|
||||
TangemPayCashbackNavigation.Accruals -> CashbackBottomSheetComponent(
|
||||
appComponentContext = context,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
content = {
|
||||
val state by model.accrualsSheet.collectAsStateWithLifecycle()
|
||||
TangemPayCashbackAccrualsBottomSheet(
|
||||
state = state,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
internal object CashbackRates {
|
||||
|
||||
private val byTier = mapOf(
|
||||
"basic" to 1,
|
||||
"plus" to 2,
|
||||
)
|
||||
|
||||
fun forTier(tier: String): Int? = byTier[tier.lowercase(Locale.ROOT)]
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlan
|
||||
|
||||
/** Cashback program tier, mapped once from the domain and shared by the rate tile and the details sheet. */
|
||||
internal data class CashbackTier(
|
||||
val planType: TangemPayTariffPlan.Type,
|
||||
val rate: Int?,
|
||||
val label: String,
|
||||
val scope: String,
|
||||
val minPurchase: String?,
|
||||
val monthlyCap: String?,
|
||||
)
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.pay.model.CashbackDocument
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackAccrualsUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class TangemPayCashbackAccrualsConverter(
|
||||
private val onDocClick: (url: String) -> Unit,
|
||||
) : Converter<List<CashbackDocument>, TangemPayCashbackAccrualsUM> {
|
||||
|
||||
// TODO([REDACTED_TASK_KEY]): move hardcoded strings to string resources
|
||||
override fun convert(value: List<CashbackDocument>): TangemPayCashbackAccrualsUM {
|
||||
return TangemPayCashbackAccrualsUM(
|
||||
title = stringReference("Accruals"),
|
||||
infoRows = INFO_ROWS,
|
||||
docRows = value.map { doc ->
|
||||
TangemPayCashbackAccrualsUM.DocRow(
|
||||
title = stringReference(doc.title),
|
||||
onClick = { onDocClick(doc.url) },
|
||||
)
|
||||
}.toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val INFO_ROWS = persistentListOf(
|
||||
TangemPayCashbackAccrualsUM.InfoRow(
|
||||
title = stringReference("How we calculate cashback?"),
|
||||
description = stringReference(
|
||||
"We process purchases within 5 days after the operation and count only completed transactions",
|
||||
),
|
||||
),
|
||||
TangemPayCashbackAccrualsUM.InfoRow(
|
||||
title = stringReference("How we pay cashback?"),
|
||||
description = stringReference("From the 2nd and the 5th of the next month"),
|
||||
),
|
||||
TangemPayCashbackAccrualsUM.InfoRow(
|
||||
title = stringReference("Exceptions"),
|
||||
description = stringReference(
|
||||
"No cashback will be awarded for in-person/in-store purchases at EU merchants; also for " +
|
||||
"withdrawals, transfers, quasi-cash, mobile phone bills, government services and certain " +
|
||||
"other categories",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackDetailsUM
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class TangemPayCashbackDetailsConverter : Converter<List<CashbackTier>, TangemPayCashbackDetailsUM> {
|
||||
|
||||
// TODO([REDACTED_TASK_KEY]): move hardcoded strings to string resources
|
||||
override fun convert(value: List<CashbackTier>): TangemPayCashbackDetailsUM {
|
||||
return TangemPayCashbackDetailsUM(
|
||||
title = title(value),
|
||||
rows = value.map(::tierRow).toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun title(tiers: List<CashbackTier>): TextReference {
|
||||
val rates = tiers.mapNotNull { it.rate }
|
||||
return when {
|
||||
rates.isEmpty() -> stringReference("Cashback")
|
||||
rates.size == 1 -> stringReference("Cashback ${rates.single()}%")
|
||||
else -> stringReference("Cashback up to ${rates.max()}%")
|
||||
}
|
||||
}
|
||||
|
||||
private fun tierRow(tier: CashbackTier): TextReference {
|
||||
val rate = tier.rate?.let { "$it% for " }.orEmpty()
|
||||
val min = tier.minPurchase?.let { ", min purchase $it" }.orEmpty()
|
||||
val cap = tier.monthlyCap?.let { ", up to $it per month" }.orEmpty()
|
||||
return stringReference("$rate${tier.scope} with your ${tier.label}$min$cap")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlan
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackInfoTilesUM
|
||||
|
||||
internal class TangemPayCashbackInfoTilesConverter(
|
||||
private val onRateClick: () -> Unit,
|
||||
private val onAccrualsClick: () -> Unit,
|
||||
) {
|
||||
|
||||
// TODO([REDACTED_TASK_KEY]): move hardcoded strings to string resources
|
||||
fun convert(
|
||||
tiers: List<CashbackTier>,
|
||||
currentPlanType: TangemPayTariffPlan.Type,
|
||||
currentPlanName: String?,
|
||||
): TangemPayCashbackInfoTilesUM {
|
||||
val rate = tiers.selectTier(currentPlanType)?.rate
|
||||
return TangemPayCashbackInfoTilesUM(
|
||||
rate = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = R.drawable.ic_percent_24,
|
||||
title = stringReference(if (rate != null) "Cashback $rate%" else "Cashback"),
|
||||
subtitle = currentPlanName?.let { stringReference("With your $it plan") } ?: TextReference.EMPTY,
|
||||
onClick = onRateClick,
|
||||
),
|
||||
accruals = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = R.drawable.ic_information_24,
|
||||
title = stringReference("Accruals"),
|
||||
subtitle = stringReference("Limits and exceptions"),
|
||||
onClick = onAccrualsClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<CashbackTier>.selectTier(planType: TangemPayTariffPlan.Type): CashbackTier? {
|
||||
return firstOrNull {
|
||||
planType != TangemPayTariffPlan.Type.UNKNOWN && it.planType == planType
|
||||
} ?: firstOrNull()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +1,114 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
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.domain.pay.model.TangemPayCashback
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackUM
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlan
|
||||
import com.tangem.domain.pay.model.CashbackDocument
|
||||
import com.tangem.domain.pay.model.CashbackPromotions
|
||||
import com.tangem.domain.pay.model.CashbackSummary
|
||||
import com.tangem.domain.pay.repository.CashbackRepository
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.features.tangempay.cashback.api.TangemPayCashbackComponent
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackAccrualsUM
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackDetailsUM
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackScreenUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.runSuspendCatching
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class TangemPayCashbackModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
paramsContainer: ParamsContainer,
|
||||
private val router: Router,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val cashbackRepository: CashbackRepository,
|
||||
private val onboardingRepository: OnboardingRepository,
|
||||
) : Model() {
|
||||
|
||||
private val params: TangemPayCashbackComponent.Params = paramsContainer.require()
|
||||
private val userWalletId get() = params.userWalletId
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TangemPayCashbackNavigation> = SlotNavigation()
|
||||
|
||||
private val cashbackConverter = TangemPayCashbackUmConverter(onCloseClick = router::pop)
|
||||
private val tiersConverter = TangemPayCashbackTiersConverter()
|
||||
private val infoTilesConverter = TangemPayCashbackInfoTilesConverter(
|
||||
onRateClick = { bottomSheetNavigation.activate(TangemPayCashbackNavigation.Details) },
|
||||
onAccrualsClick = { bottomSheetNavigation.activate(TangemPayCashbackNavigation.Accruals) },
|
||||
)
|
||||
private val detailsConverter = TangemPayCashbackDetailsConverter()
|
||||
private val accrualsConverter = TangemPayCashbackAccrualsConverter(onDocClick = urlOpener::openUrl)
|
||||
|
||||
val uiState: StateFlow<TangemPayCashbackUM>
|
||||
field = MutableStateFlow(cashbackConverter.convert(STUB_CASHBACK))
|
||||
val detailsSheet: StateFlow<TangemPayCashbackDetailsUM>
|
||||
field = MutableStateFlow(detailsConverter.convert(emptyList()))
|
||||
|
||||
private companion object {
|
||||
// TODO([REDACTED_TASK_KEY]): replace stub with repository load
|
||||
val STUB_CASHBACK = TangemPayCashback(
|
||||
confirmedAmount = BigDecimal("22.54"),
|
||||
pendingAmount = BigDecimal("13.65"),
|
||||
currency = "USD",
|
||||
payoutCurrency = "USDC",
|
||||
payoutNetwork = "Polygon",
|
||||
period = TangemPayCashback.Period(
|
||||
year = 2026,
|
||||
month = 6,
|
||||
payoutStart = DateTime.parse("2026-07-01"),
|
||||
payoutEnd = DateTime.parse("2026-07-05"),
|
||||
val accrualsSheet: StateFlow<TangemPayCashbackAccrualsUM>
|
||||
field = MutableStateFlow(accrualsConverter.convert(emptyList()))
|
||||
|
||||
val uiState: StateFlow<TangemPayCashbackScreenUM>
|
||||
field = MutableStateFlow(
|
||||
TangemPayCashbackScreenUM(
|
||||
cashback = cashbackConverter.convert(value = null),
|
||||
infoTiles = null,
|
||||
),
|
||||
)
|
||||
|
||||
init {
|
||||
loadCashback()
|
||||
}
|
||||
|
||||
private fun loadCashback() {
|
||||
modelScope.launch {
|
||||
val summaryDeferred = async { loadSummary() }
|
||||
val promotionsDeferred = async { loadPromotions() }
|
||||
val docsDeferred = async { loadDocs() }
|
||||
val planDeferred = async { loadPlan() }
|
||||
|
||||
val summary = summaryDeferred.await()
|
||||
val promotions = promotionsDeferred.await()
|
||||
val plan = planDeferred.await()
|
||||
val tiers = promotions?.let(tiersConverter::convert).orEmpty()
|
||||
|
||||
uiState.value = TangemPayCashbackScreenUM(
|
||||
cashback = cashbackConverter.convert((summary as? CashbackSummary.Enabled)?.cashback),
|
||||
infoTiles = promotions?.let {
|
||||
infoTilesConverter.convert(
|
||||
tiers = tiers,
|
||||
currentPlanType = plan?.type ?: TangemPayTariffPlan.Type.UNKNOWN,
|
||||
currentPlanName = plan?.name,
|
||||
)
|
||||
},
|
||||
)
|
||||
detailsSheet.value = detailsConverter.convert(tiers)
|
||||
accrualsSheet.value = accrualsConverter.convert(docsDeferred.await())
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadSummary(): CashbackSummary? =
|
||||
runSuspendCatching { cashbackRepository.getCashbackSummary(userWalletId).getOrNull() }.getOrNull()
|
||||
|
||||
private suspend fun loadPromotions(): CashbackPromotions? =
|
||||
runSuspendCatching { cashbackRepository.getCashbackPromotions(userWalletId).getOrNull() }.getOrNull()
|
||||
|
||||
private suspend fun loadDocs(): List<CashbackDocument> =
|
||||
runSuspendCatching { cashbackRepository.getCashbackAccrualDocs(userWalletId).getOrNull() }
|
||||
.getOrNull().orEmpty()
|
||||
|
||||
private suspend fun loadPlan(): TangemPayTariffPlan? {
|
||||
return runSuspendCatching {
|
||||
onboardingRepository.getCustomerInfo(userWalletId).getOrNull()
|
||||
}.getOrNull()?.tariffPlan?.plan
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal sealed class TangemPayCashbackNavigation {
|
||||
|
||||
@Serializable
|
||||
data object Details : TangemPayCashbackNavigation()
|
||||
|
||||
@Serializable
|
||||
data object Accruals : TangemPayCashbackNavigation()
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.model
|
||||
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode
|
||||
import com.tangem.core.ui.format.bigdecimal.optionalDecimals
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlan
|
||||
import com.tangem.domain.pay.model.CashbackPromotions
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class TangemPayCashbackTiersConverter : Converter<CashbackPromotions, List<CashbackTier>> {
|
||||
|
||||
override fun convert(value: CashbackPromotions): List<CashbackTier> {
|
||||
return value.cardTiers.map { tier ->
|
||||
CashbackTier(
|
||||
planType = TangemPayTariffPlan.Type.fromString(tier.tier),
|
||||
rate = CashbackRates.forTier(tier.tier),
|
||||
label = tier.label,
|
||||
scope = tier.scope,
|
||||
minPurchase = tier.minTransactionAmount?.formatUsd(),
|
||||
monthlyCap = tier.monthlyCapAmount?.formatUsd(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BigDecimal.formatUsd(): String {
|
||||
val currency = getJavaCurrencyByCode(AMOUNT_CURRENCY_CODE)
|
||||
return format { fiat(currency.currencyCode, currency.symbol).optionalDecimals() }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val AMOUNT_CURRENCY_CODE = "USD"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.runtime.Composable
|
||||
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.core.ui.components.bottomsheets.TangemBottomSheetType
|
||||
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun CashbackBottomSheet(title: TextReference, onDismiss: () -> Unit, content: @Composable () -> Unit) {
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onDismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
type = TangemBottomSheetType.Modal,
|
||||
containerColor = TangemTheme.colors3.bg.secondary,
|
||||
title = {
|
||||
TangemTopNavigation(
|
||||
title = title,
|
||||
contentAlign = TangemTopNavigation.ContentAlign.Center,
|
||||
windowInsets = WindowInsets(0),
|
||||
onClose = onDismiss,
|
||||
)
|
||||
},
|
||||
content = { content() },
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds2.row.TangemRow
|
||||
import com.tangem.core.ui.ds2.row.TangemRowText
|
||||
import com.tangem.core.ui.ds2.row.TangemRowTextRole
|
||||
import com.tangem.core.ui.ds2.row.TangemRowVerticalAlignment
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackAccrualsUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCashbackAccrualsBottomSheet(state: TangemPayCashbackAccrualsUM, onDismiss: () -> Unit) {
|
||||
CashbackBottomSheet(title = state.title, onDismiss = onDismiss) {
|
||||
AccrualsContent(state)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AccrualsContent(state: TangemPayCashbackAccrualsUM) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
) {
|
||||
state.infoRows.forEach { row ->
|
||||
TangemRow(
|
||||
verticalAlignment = TangemRowVerticalAlignment.Top,
|
||||
startSlot = {
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(id = R.drawable.ic_information_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.primary,
|
||||
)
|
||||
},
|
||||
titleSlot = { TangemRowText(text = row.title, role = TangemRowTextRole.Title) },
|
||||
subtitleSlot = {
|
||||
TangemRowText(text = row.description, role = TangemRowTextRole.Subtitle, maxLines = Int.MAX_VALUE)
|
||||
},
|
||||
divider = true,
|
||||
)
|
||||
}
|
||||
state.docRows.forEachIndexed { index, row ->
|
||||
TangemRow(
|
||||
verticalAlignment = TangemRowVerticalAlignment.Center,
|
||||
startSlot = {
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(id = R.drawable.ic_doc_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.primary,
|
||||
)
|
||||
},
|
||||
titleSlot = { TangemRowText(text = row.title, role = TangemRowTextRole.Title) },
|
||||
endSlot = {
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.secondary,
|
||||
)
|
||||
},
|
||||
onClick = row.onClick,
|
||||
divider = index < state.docRows.lastIndex,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 402)
|
||||
@Preview(showBackground = true, widthDp = 402, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayCashbackAccrualsBottomSheetPreview(
|
||||
@PreviewParameter(TangemPayCashbackAccrualsPreviewProvider::class) state: TangemPayCashbackAccrualsUM,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors3.bg.secondary),
|
||||
) {
|
||||
AccrualsContent(state = state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TangemPayCashbackAccrualsPreviewProvider :
|
||||
CollectionPreviewParameterProvider<TangemPayCashbackAccrualsUM>(
|
||||
listOf(
|
||||
TangemPayCashbackAccrualsUM(
|
||||
title = stringReference("Accruals"),
|
||||
infoRows = previewInfoRows(),
|
||||
docRows = persistentListOf(
|
||||
TangemPayCashbackAccrualsUM.DocRow(
|
||||
title = stringReference("All categories without cashback"),
|
||||
onClick = {},
|
||||
),
|
||||
TangemPayCashbackAccrualsUM.DocRow(
|
||||
title = stringReference("Full terms of cashback program"),
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
),
|
||||
TangemPayCashbackAccrualsUM(
|
||||
title = stringReference("Accruals"),
|
||||
infoRows = previewInfoRows(),
|
||||
docRows = persistentListOf(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
private fun previewInfoRows() = persistentListOf(
|
||||
TangemPayCashbackAccrualsUM.InfoRow(
|
||||
title = stringReference("How we calculate cashback?"),
|
||||
description = stringReference(
|
||||
"We process purchases within 5 days after the operation and count only completed transactions",
|
||||
),
|
||||
),
|
||||
TangemPayCashbackAccrualsUM.InfoRow(
|
||||
title = stringReference("How we pay cashback?"),
|
||||
description = stringReference("From the 2nd and the 5th of the next month"),
|
||||
),
|
||||
TangemPayCashbackAccrualsUM.InfoRow(
|
||||
title = stringReference("Exceptions"),
|
||||
description = stringReference(
|
||||
"No cashback will be awarded for in-person/in-store purchases at EU merchants; also for " +
|
||||
"withdrawals, transfers, quasi-cash, mobile phone bills, government services and certain " +
|
||||
"other categories",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds2.row.TangemRow
|
||||
import com.tangem.core.ui.ds2.row.TangemRowText
|
||||
import com.tangem.core.ui.ds2.row.TangemRowTextRole
|
||||
import com.tangem.core.ui.ds2.row.TangemRowVerticalAlignment
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackDetailsUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCashbackDetailsBottomSheet(state: TangemPayCashbackDetailsUM, onDismiss: () -> Unit) {
|
||||
CashbackBottomSheet(title = state.title, onDismiss = onDismiss) {
|
||||
DetailsContent(state)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DetailsContent(state: TangemPayCashbackDetailsUM) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
) {
|
||||
state.rows.forEachIndexed { index, row ->
|
||||
TangemRow(
|
||||
verticalAlignment = TangemRowVerticalAlignment.Top,
|
||||
startSlot = {
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(id = R.drawable.ic_information_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.primary,
|
||||
)
|
||||
},
|
||||
titleSlot = { TangemRowText(text = row, role = TangemRowTextRole.Title, maxLines = Int.MAX_VALUE) },
|
||||
divider = index < state.rows.lastIndex,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 402)
|
||||
@Preview(showBackground = true, widthDp = 402, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayCashbackDetailsBottomSheetPreview(
|
||||
@PreviewParameter(TangemPayCashbackDetailsPreviewProvider::class) state: TangemPayCashbackDetailsUM,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors3.bg.secondary),
|
||||
) {
|
||||
DetailsContent(state = state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TangemPayCashbackDetailsPreviewProvider : CollectionPreviewParameterProvider<TangemPayCashbackDetailsUM>(
|
||||
listOf(
|
||||
TangemPayCashbackDetailsUM(
|
||||
title = stringReference("Cashback up to 2%"),
|
||||
rows = persistentListOf<TextReference>(
|
||||
stringReference("1% for All purchases with your Basic cards, min purchase $30, up to $100 per month"),
|
||||
stringReference("2% for All purchases with your Plus cards, min purchase $30, up to $300 per month"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds2.surface.TangemSurface
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackInfoTilesUM
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCashbackInfoTiles(state: TangemPayCashbackInfoTilesUM, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Tile(
|
||||
tile = state.rate,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight(),
|
||||
)
|
||||
Tile(
|
||||
tile = state.accruals,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Tile(tile: TangemPayCashbackInfoTilesUM.Tile, modifier: Modifier = Modifier) {
|
||||
TangemSurface(
|
||||
modifier = modifier,
|
||||
color = TangemTheme.colors3.bg.secondary,
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
onClick = tile.onClick,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(CircleShape)
|
||||
.background(TangemTheme.colors3.bg.tertiary),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
painter = painterResource(id = tile.iconRes),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.primary,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
|
||||
Text(
|
||||
text = tile.title.resolveReference(),
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
)
|
||||
Text(
|
||||
text = tile.subtitle.resolveReference(),
|
||||
style = TangemTheme.typography3.caption.medium,
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 402)
|
||||
@Preview(showBackground = true, widthDp = 402, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayCashbackInfoTilesPreview(
|
||||
@PreviewParameter(TangemPayCashbackInfoTilesPreviewProvider::class) state: TangemPayCashbackInfoTilesUM,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors3.bg.primary)
|
||||
.padding(vertical = 16.dp),
|
||||
) {
|
||||
TangemPayCashbackInfoTiles(state = state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TangemPayCashbackInfoTilesPreviewProvider :
|
||||
CollectionPreviewParameterProvider<TangemPayCashbackInfoTilesUM>(
|
||||
listOf(
|
||||
TangemPayCashbackInfoTilesUM(
|
||||
rate = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = R.drawable.ic_percent_24,
|
||||
title = stringReference("Cashback 1%"),
|
||||
subtitle = stringReference("With your Basic plan"),
|
||||
onClick = {},
|
||||
),
|
||||
accruals = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = R.drawable.ic_information_24,
|
||||
title = stringReference("Accruals"),
|
||||
subtitle = stringReference("Limits and exceptions"),
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
TangemPayCashbackInfoTilesUM(
|
||||
rate = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = R.drawable.ic_percent_24,
|
||||
title = stringReference("Cashback up to 2%"),
|
||||
subtitle = stringReference("With your Plus plan"),
|
||||
onClick = {},
|
||||
),
|
||||
accruals = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = R.drawable.ic_information_24,
|
||||
title = stringReference("Accruals"),
|
||||
subtitle = stringReference("Limits and exceptions"),
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -10,15 +10,12 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
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.draw.BlurredEdgeTreatment
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
|
|
@ -31,16 +28,17 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds2.button.TangemButton
|
||||
import com.tangem.core.ui.components.haze.hazeForegroundEffectTangem
|
||||
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.LocalIsInDarkTheme
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackInfoTilesUM
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackScreenUM
|
||||
import com.tangem.features.tangempay.cashback.impl.ui.state.TangemPayCashbackUM
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import dev.chrisbanes.haze.HazeStyle
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
private const val GLOW_RADIUS_FACTOR = 0.585f
|
||||
|
|
@ -48,31 +46,24 @@ private const val GLOW_BLUE_ALPHA = 0.20f
|
|||
private const val GLOW_WARM_ALPHA = 0.15f
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCashbackScreen(state: TangemPayCashbackUM, modifier: Modifier = Modifier) {
|
||||
internal fun TangemPayCashbackScreen(state: TangemPayCashbackScreenUM, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(TangemTheme.colors3.bg.primary),
|
||||
) {
|
||||
if (state.isEmpty) {
|
||||
if (state.cashback.isEmpty) {
|
||||
EmptyStateGlow(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
TangemTopBar(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
TangemTopNavigation(
|
||||
// TODO([REDACTED_TASK_KEY]): move to string resources
|
||||
title = stringReference("Cashback"),
|
||||
endContent = {
|
||||
TangemButton(
|
||||
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_close_24),
|
||||
onClick = state.onCloseClick,
|
||||
size = TangemButton.Size.X11,
|
||||
variant = TangemButton.Variant.Material,
|
||||
)
|
||||
},
|
||||
contentAlign = TangemTopNavigation.ContentAlign.Center,
|
||||
onClose = state.cashback.onCloseClick,
|
||||
)
|
||||
HeroBlock(state = state)
|
||||
state.banner?.let { banner ->
|
||||
HeroBlock(state = state.cashback)
|
||||
state.cashback.banner?.let { banner ->
|
||||
CashbackBanner(
|
||||
banner = banner,
|
||||
modifier = Modifier
|
||||
|
|
@ -80,6 +71,12 @@ internal fun TangemPayCashbackScreen(state: TangemPayCashbackUM, modifier: Modif
|
|||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
state.infoTiles?.let { infoTiles ->
|
||||
TangemPayCashbackInfoTiles(
|
||||
state = infoTiles,
|
||||
modifier = Modifier.padding(top = 24.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +89,7 @@ private fun EmptyStateGlow(modifier: Modifier = Modifier) {
|
|||
val blue = if (isDark) Color(0xFF0090F9) else Color(0xFF0092FC)
|
||||
Box(
|
||||
modifier = modifier
|
||||
.blur(56.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded)
|
||||
.hazeForegroundEffectTangem(style = HazeStyle(blurRadius = 56.dp, tint = null))
|
||||
.drawBehind {
|
||||
val radius = size.width * GLOW_RADIUS_FACTOR
|
||||
val center = Offset(x = size.width / 2f, y = 0f)
|
||||
|
|
@ -175,43 +172,67 @@ private fun CashbackBanner(banner: TangemPayCashbackUM.Banner, modifier: Modifie
|
|||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_7_PRO)
|
||||
@Composable
|
||||
private fun TangemPayCashbackScreenPreview(
|
||||
@PreviewParameter(TangemPayCashbackUMProvider::class) state: TangemPayCashbackUM,
|
||||
@PreviewParameter(TangemPayCashbackScreenUMProvider::class) state: TangemPayCashbackScreenUM,
|
||||
) {
|
||||
TangemThemePreviewRedesign {
|
||||
TangemPayCashbackScreen(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
private class TangemPayCashbackUMProvider : CollectionPreviewParameterProvider<TangemPayCashbackUM>(
|
||||
private class TangemPayCashbackScreenUMProvider : CollectionPreviewParameterProvider<TangemPayCashbackScreenUM>(
|
||||
collection = listOf(
|
||||
TangemPayCashbackUM(
|
||||
title = stringReference("$22.54 earned in June"),
|
||||
subtitle = stringReference("Will be deposited on July 1–5"),
|
||||
isEmpty = false,
|
||||
banner = TangemPayCashbackUM.Banner(
|
||||
text = stringReference("Cashback $22.54 for June will be deposited till July 5"),
|
||||
type = TangemPayCashbackUM.Banner.Type.Info,
|
||||
),
|
||||
onCloseClick = {},
|
||||
),
|
||||
TangemPayCashbackUM(
|
||||
title = stringReference("$22.54 earned in June"),
|
||||
subtitle = stringReference("Will be deposited on July 1–5"),
|
||||
isEmpty = false,
|
||||
banner = TangemPayCashbackUM.Banner(
|
||||
text = stringReference(
|
||||
"We received a refund for a purchase for which cashback had previously been awarded",
|
||||
TangemPayCashbackScreenUM(
|
||||
cashback = TangemPayCashbackUM(
|
||||
title = stringReference("$22.54 earned in June"),
|
||||
subtitle = stringReference("Will be deposited on July 1–5"),
|
||||
isEmpty = false,
|
||||
banner = TangemPayCashbackUM.Banner(
|
||||
text = stringReference("Cashback $22.54 for June will be deposited till July 5"),
|
||||
type = TangemPayCashbackUM.Banner.Type.Info,
|
||||
),
|
||||
type = TangemPayCashbackUM.Banner.Type.Error,
|
||||
onCloseClick = {},
|
||||
),
|
||||
onCloseClick = {},
|
||||
infoTiles = previewInfoTiles(),
|
||||
),
|
||||
TangemPayCashbackUM(
|
||||
title = stringReference("Start spending and earn cashback"),
|
||||
subtitle = stringReference("Collected amount will be shown here"),
|
||||
isEmpty = true,
|
||||
banner = null,
|
||||
onCloseClick = {},
|
||||
TangemPayCashbackScreenUM(
|
||||
cashback = TangemPayCashbackUM(
|
||||
title = stringReference("$22.54 earned in June"),
|
||||
subtitle = stringReference("Will be deposited on July 1–5"),
|
||||
isEmpty = false,
|
||||
banner = TangemPayCashbackUM.Banner(
|
||||
text = stringReference(
|
||||
"We received a refund for a purchase for which cashback had previously been awarded",
|
||||
),
|
||||
type = TangemPayCashbackUM.Banner.Type.Error,
|
||||
),
|
||||
onCloseClick = {},
|
||||
),
|
||||
infoTiles = null,
|
||||
),
|
||||
TangemPayCashbackScreenUM(
|
||||
cashback = TangemPayCashbackUM(
|
||||
title = stringReference("Start spending and earn cashback"),
|
||||
subtitle = stringReference("Collected amount will be shown here"),
|
||||
isEmpty = true,
|
||||
banner = null,
|
||||
onCloseClick = {},
|
||||
),
|
||||
infoTiles = null,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
private fun previewInfoTiles() = TangemPayCashbackInfoTilesUM(
|
||||
rate = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = CoreUiR.drawable.ic_percent_24,
|
||||
title = stringReference("Cashback 1%"),
|
||||
subtitle = stringReference("With your Basic plan"),
|
||||
onClick = {},
|
||||
),
|
||||
accruals = TangemPayCashbackInfoTilesUM.Tile(
|
||||
iconRes = CoreUiR.drawable.ic_information_24,
|
||||
title = stringReference("Accruals"),
|
||||
subtitle = stringReference("Limits and exceptions"),
|
||||
onClick = {},
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
data class TangemPayCashbackAccrualsUM(
|
||||
val title: TextReference,
|
||||
val infoRows: ImmutableList<InfoRow>,
|
||||
val docRows: ImmutableList<DocRow>,
|
||||
) {
|
||||
|
||||
@Immutable
|
||||
data class InfoRow(
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class DocRow(
|
||||
val title: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal data class TangemPayCashbackDetailsUM(
|
||||
val title: TextReference,
|
||||
val rows: ImmutableList<TextReference>,
|
||||
)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui.state
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
data class TangemPayCashbackInfoTilesUM(
|
||||
val rate: Tile,
|
||||
val accruals: Tile,
|
||||
) {
|
||||
|
||||
@Immutable
|
||||
data class Tile(
|
||||
@DrawableRes val iconRes: Int,
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.features.tangempay.cashback.impl.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
internal data class TangemPayCashbackScreenUM(
|
||||
val cashback: TangemPayCashbackUM,
|
||||
val infoTiles: TangemPayCashbackInfoTilesUM?,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue