Updated on 2026-08-14
This commit is contained in:
parent
2debaafcbb
commit
cf61439729
25 changed files with 1127 additions and 235 deletions
|
|
@ -49,11 +49,11 @@ data class MessageBottomSheetUM(
|
||||||
var backgroundType: BackgroundType = BackgroundType.Unspecified,
|
var backgroundType: BackgroundType = BackgroundType.Unspecified,
|
||||||
) : Element {
|
) : Element {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Unspecified, Accent, Informative, Attention, Warning,
|
Unspecified, Accent, Informative, Attention, Warning, Success,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class BackgroundType {
|
enum class BackgroundType {
|
||||||
Unspecified, SameAsTint, Accent, Informative, Attention, Warning,
|
Unspecified, SameAsTint, Accent, Informative, Attention, Warning, Success,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ private fun BottomSheetVector(vector: MessageBottomSheetUM.Vector, modifier: Mod
|
||||||
MessageBottomSheetUM.Vector.Type.Informative -> TangemTheme.colors3.icon.status.info
|
MessageBottomSheetUM.Vector.Type.Informative -> TangemTheme.colors3.icon.status.info
|
||||||
MessageBottomSheetUM.Vector.Type.Attention -> TangemTheme.colors3.icon.status.warning
|
MessageBottomSheetUM.Vector.Type.Attention -> TangemTheme.colors3.icon.status.warning
|
||||||
MessageBottomSheetUM.Vector.Type.Warning -> TangemTheme.colors3.icon.status.error
|
MessageBottomSheetUM.Vector.Type.Warning -> TangemTheme.colors3.icon.status.error
|
||||||
|
MessageBottomSheetUM.Vector.Type.Success -> TangemTheme.colors3.icon.status.success
|
||||||
}
|
}
|
||||||
|
|
||||||
val backgroundColor = when (vector.backgroundType) {
|
val backgroundColor = when (vector.backgroundType) {
|
||||||
|
|
@ -223,6 +224,7 @@ private fun BottomSheetVector(vector: MessageBottomSheetUM.Vector, modifier: Mod
|
||||||
MessageBottomSheetUM.Vector.BackgroundType.Informative -> TangemTheme.colors3.bg.status.infoSubtle
|
MessageBottomSheetUM.Vector.BackgroundType.Informative -> TangemTheme.colors3.bg.status.infoSubtle
|
||||||
MessageBottomSheetUM.Vector.BackgroundType.Attention -> TangemTheme.colors3.bg.status.warningSubtle
|
MessageBottomSheetUM.Vector.BackgroundType.Attention -> TangemTheme.colors3.bg.status.warningSubtle
|
||||||
MessageBottomSheetUM.Vector.BackgroundType.Warning -> TangemTheme.colors3.bg.status.errorSubtle
|
MessageBottomSheetUM.Vector.BackgroundType.Warning -> TangemTheme.colors3.bg.status.errorSubtle
|
||||||
|
MessageBottomSheetUM.Vector.BackgroundType.Success -> TangemTheme.colors3.bg.status.successSubtle
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ dependencies {
|
||||||
api(projects.domain.common)
|
api(projects.domain.common)
|
||||||
implementation(projects.domain.models)
|
implementation(projects.domain.models)
|
||||||
implementation(projects.domain.appCurrency)
|
implementation(projects.domain.appCurrency)
|
||||||
|
implementation(projects.domain.account.status)
|
||||||
|
|
||||||
/** Core */
|
/** Core */
|
||||||
api(projects.core.configToggles)
|
api(projects.core.configToggles)
|
||||||
|
|
@ -56,4 +57,5 @@ dependencies {
|
||||||
/** Tests */
|
/** Tests */
|
||||||
testImplementation(deps.test.junit5)
|
testImplementation(deps.test.junit5)
|
||||||
testImplementation(deps.test.truth)
|
testImplementation(deps.test.truth)
|
||||||
|
testImplementation(deps.kotlin.serialization)
|
||||||
}
|
}
|
||||||
|
|
@ -1,26 +1,33 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.component
|
package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.child
|
import com.tangem.core.decompose.context.child
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
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.TangemBottomSheetConfig
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
import com.tangem.core.ui.ds2.button.Close
|
||||||
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
|
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||||
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
|
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
|
||||||
import com.tangem.features.promobanners.impl.campaigns.ui.ActivateCampaignContent
|
import com.tangem.features.promobanners.impl.campaigns.ui.ActivateCampaignContent
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.ui.ActivateCampaignFooter
|
||||||
|
|
||||||
internal class ActivateCampaignBottomSheetComponent(
|
internal class ActivateCampaignBottomSheetComponent(
|
||||||
appComponentContext: AppComponentContext,
|
appComponentContext: AppComponentContext,
|
||||||
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
||||||
params: ActivateCampaignsModel.Params,
|
private val params: ActivateCampaignsModel.Params,
|
||||||
) : ComposableBottomSheetComponent, AppComponentContext by appComponentContext {
|
) : CampaignsModularComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val model: ActivateCampaignsModel = getOrCreateModel(params)
|
private val model: ActivateCampaignsModel = getOrCreateModel(params)
|
||||||
|
|
||||||
|
|
@ -29,36 +36,45 @@ internal class ActivateCampaignBottomSheetComponent(
|
||||||
params = ChooseTokenComponent.Params(bridge = model.bridge),
|
params = ChooseTokenComponent.Params(bridge = model.bridge),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun dismiss() = model.onDismiss()
|
@Composable
|
||||||
|
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||||
|
TangemTopNavigation(
|
||||||
|
windowInsets = WindowInsets(0),
|
||||||
|
blurBackground = false,
|
||||||
|
endButton = { TangemButton.Close(onClick = params.onDismiss) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun BottomSheet() {
|
override fun Content(bottomSheetState: State<BottomSheetState>, contentPadding: PaddingValues, modifier: Modifier) {
|
||||||
val state by model.uiState.collectAsStateWithLifecycle()
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
ActivateCampaignContent(
|
ActivateCampaignContent(um = state)
|
||||||
state = state,
|
|
||||||
onSelectTokenClick = model::onSelectTokenClick,
|
|
||||||
onEnrollClick = model::onEnrollClick,
|
|
||||||
onLearnMoreClick = { /* [REDACTED_TODO_COMMENT] */ },
|
|
||||||
onDismiss = ::dismiss,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (state.isChoosingToken) {
|
if (state.isChoosingToken) {
|
||||||
ChooseTokenBottomSheet()
|
ChooseTokenBottomSheet(state.onChooseTokenDismiss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ChooseTokenBottomSheet() {
|
override fun Footer() {
|
||||||
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
ActivateCampaignFooter(
|
||||||
|
footerUM = state.footerUM,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ChooseTokenBottomSheet(onChooseTokenDismiss: () -> Unit) {
|
||||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||||
config = TangemBottomSheetConfig(
|
config = TangemBottomSheetConfig(
|
||||||
isShown = true,
|
isShown = true,
|
||||||
onDismissRequest = model::onChooseTokenDismiss,
|
onDismissRequest = onChooseTokenDismiss,
|
||||||
content = TangemBottomSheetConfigContent.Empty,
|
content = TangemBottomSheetConfigContent.Empty,
|
||||||
),
|
),
|
||||||
onBack = model::onChooseTokenDismiss,
|
onBack = onChooseTokenDismiss,
|
||||||
) {
|
content = { chooseTokenComponent.Content(modifier = Modifier.fillMaxWidth()) },
|
||||||
chooseTokenComponent.Content(modifier = Modifier.fillMaxWidth())
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||||
|
import com.tangem.core.ui.ds2.button.Close
|
||||||
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
|
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
|
import com.tangem.features.promobanners.impl.R
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.model.CampaignAlreadyActivatedModel
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.ui.ActivateCampaignContent
|
||||||
|
|
||||||
|
internal class CampaignAlreadyActivatedBottomSheetComponent(
|
||||||
|
appComponentContext: AppComponentContext,
|
||||||
|
private val params: CampaignAlreadyActivatedModel.Params,
|
||||||
|
) : CampaignsModularComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
|
private val model: CampaignAlreadyActivatedModel = getOrCreateModel(params)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||||
|
TangemTopNavigation(
|
||||||
|
windowInsets = WindowInsets(0),
|
||||||
|
blurBackground = false,
|
||||||
|
endButton = { TangemButton.Close(onClick = params.onDismiss) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content(bottomSheetState: State<BottomSheetState>, contentPadding: PaddingValues, modifier: Modifier) {
|
||||||
|
val state by model.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
ActivateCampaignContent(um = state)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Footer() {
|
||||||
|
PrimaryButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = stringResourceSafe(R.string.common_close),
|
||||||
|
onClick = params.onDismiss,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,50 +1,50 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.component
|
package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheet
|
import androidx.compose.runtime.State
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUM
|
import androidx.compose.ui.Modifier
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.infoBlock
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.messageBottomSheetUM
|
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.onClick
|
import com.tangem.core.ui.ds2.button.Close
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.onDismiss
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.primaryButton
|
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.vector
|
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.res.generated.icons.Icons
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.res.generated.icons.ic_success_24
|
|
||||||
import com.tangem.features.promobanners.impl.R
|
import com.tangem.features.promobanners.impl.R
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.campaignName
|
import com.tangem.features.promobanners.impl.campaigns.entity.campaignName
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.ui.CampaignEnrolledMessageContent
|
||||||
|
|
||||||
internal class CampaignEnrolledBottomSheetComponent(
|
internal class CampaignEnrolledBottomSheetComponent(
|
||||||
private val campaignType: CampaignType,
|
private val campaignType: CampaignType,
|
||||||
private val onDismissRequest: () -> Unit,
|
private val onDismissRequest: () -> Unit,
|
||||||
) : ComposableBottomSheetComponent {
|
) : CampaignsModularComponent {
|
||||||
|
|
||||||
override fun dismiss() = onDismissRequest()
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun BottomSheet() {
|
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||||
MessageBottomSheet(
|
TangemTopNavigation(
|
||||||
state = messageBottomSheetUM {
|
windowInsets = WindowInsets(0),
|
||||||
onDismiss(onDismissRequest)
|
blurBackground = false,
|
||||||
infoBlock {
|
endButton = { TangemButton.Close(onClick = onDismissRequest) },
|
||||||
vector(Icons.ic_success_24) {
|
)
|
||||||
type = MessageBottomSheetUM.Vector.Type.Accent
|
}
|
||||||
backgroundType = MessageBottomSheetUM.Vector.BackgroundType.SameAsTint
|
|
||||||
}
|
|
||||||
|
|
||||||
title = stringReference("You're successfully enrolled in ${campaignType.campaignName()}")
|
@Composable
|
||||||
body = stringReference("Your cashback will be applied to eligible swaps automatically.")
|
override fun Content(bottomSheetState: State<BottomSheetState>, contentPadding: PaddingValues, modifier: Modifier) {
|
||||||
}
|
CampaignEnrolledMessageContent(
|
||||||
primaryButton {
|
message = stringReference("You're successfully enrolled in ${campaignType.campaignName()}"),
|
||||||
text = resourceReference(R.string.common_close)
|
)
|
||||||
onClick { closeBs() }
|
}
|
||||||
}
|
|
||||||
},
|
@Composable
|
||||||
onDismissRequest = onDismissRequest,
|
override fun Footer() {
|
||||||
|
PrimaryButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = stringResourceSafe(R.string.common_close),
|
||||||
|
onClick = { onDismissRequest() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
||||||
|
|
||||||
|
interface CampaignsModularComponent : ComposableModularBottomSheetContentComponent {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Footer()
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,36 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.component
|
package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateContentSize
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.arkivanov.decompose.ComponentContext
|
import com.arkivanov.decompose.ComponentContext
|
||||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||||
import com.arkivanov.decompose.router.slot.childSlot
|
import com.arkivanov.decompose.router.slot.childSlot
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.childByContext
|
import com.tangem.core.decompose.context.childByContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
import com.tangem.core.ui.components.bottomsheets.LocalBottomSheetContentScrollable
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||||
|
import com.tangem.core.ui.extensions.rememberLastNonNull
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
|
||||||
import com.tangem.features.promobanners.api.swapcashback.CampaignsComponent
|
import com.tangem.features.promobanners.api.swapcashback.CampaignsComponent
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignsBottomSheetConfig
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignsBottomSheetConfig
|
||||||
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
|
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.model.CampaignAlreadyActivatedModel
|
||||||
import com.tangem.features.promobanners.impl.campaigns.model.CampaignsModel
|
import com.tangem.features.promobanners.impl.campaigns.model.CampaignsModel
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
|
@ -29,7 +46,7 @@ internal class DefaultCampaignsComponent @AssistedInject constructor(
|
||||||
|
|
||||||
private val bottomSheetSlot = childSlot(
|
private val bottomSheetSlot = childSlot(
|
||||||
source = model.bottomSheetNavigation,
|
source = model.bottomSheetNavigation,
|
||||||
serializer = CampaignsBottomSheetConfig.serializer(),
|
serializer = null,
|
||||||
handleBackButton = false,
|
handleBackButton = false,
|
||||||
childFactory = ::bottomSheetChild,
|
childFactory = ::bottomSheetChild,
|
||||||
)
|
)
|
||||||
|
|
@ -37,13 +54,61 @@ internal class DefaultCampaignsComponent @AssistedInject constructor(
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content(modifier: Modifier) {
|
override fun Content(modifier: Modifier) {
|
||||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||||
bottomSheet.child?.instance?.BottomSheet()
|
val activeChild = bottomSheet.child?.instance
|
||||||
|
val displayedChild = rememberLastNonNull(activeChild)
|
||||||
|
val bottomSheetState = remember { mutableStateOf(BottomSheetState.EXPANDED) }
|
||||||
|
|
||||||
|
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||||
|
config = TangemBottomSheetConfig(
|
||||||
|
isShown = activeChild != null,
|
||||||
|
onDismissRequest = model::onDismiss,
|
||||||
|
content = TangemBottomSheetConfigContent.Empty,
|
||||||
|
),
|
||||||
|
onBack = model::onDismiss,
|
||||||
|
title = {
|
||||||
|
displayedChild?.Title(bottomSheetState)
|
||||||
|
},
|
||||||
|
content = {
|
||||||
|
val bottomInset = LocalTangemBottomSheetContentBottomInset.current
|
||||||
|
val scrollableSignal = LocalBottomSheetContentScrollable.current
|
||||||
|
|
||||||
|
if (scrollableSignal != null) {
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
scrollableSignal.value = false
|
||||||
|
}
|
||||||
|
DisposableEffect(scrollableSignal) {
|
||||||
|
onDispose { scrollableSignal.value = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(bottom = bottomInset)
|
||||||
|
.animateContentSize(),
|
||||||
|
) {
|
||||||
|
displayedChild?.Content(
|
||||||
|
bottomSheetState = bottomSheetState,
|
||||||
|
contentPadding = PaddingValues(),
|
||||||
|
modifier = Modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
footer = {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.navigationBarsPadding()
|
||||||
|
.padding(12.dp),
|
||||||
|
) {
|
||||||
|
displayedChild?.Footer()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bottomSheetChild(
|
private fun bottomSheetChild(
|
||||||
config: CampaignsBottomSheetConfig,
|
config: CampaignsBottomSheetConfig,
|
||||||
componentContext: ComponentContext,
|
componentContext: ComponentContext,
|
||||||
): ComposableBottomSheetComponent {
|
): CampaignsModularComponent {
|
||||||
val context = childByContext(componentContext)
|
val context = childByContext(componentContext)
|
||||||
return when (config) {
|
return when (config) {
|
||||||
CampaignsBottomSheetConfig.NotActive -> NotActiveCampaignBottomSheetComponent(
|
CampaignsBottomSheetConfig.NotActive -> NotActiveCampaignBottomSheetComponent(
|
||||||
|
|
@ -60,6 +125,24 @@ internal class DefaultCampaignsComponent @AssistedInject constructor(
|
||||||
campaignType = config.campaignType,
|
campaignType = config.campaignType,
|
||||||
onDismiss = model::onDismiss,
|
onDismiss = model::onDismiss,
|
||||||
onActivated = model::onActivated,
|
onActivated = model::onActivated,
|
||||||
|
onAlreadyActivated = { campaignType, appCurrency, account, currency ->
|
||||||
|
model.onAlreadyActivated(
|
||||||
|
campaignType = campaignType,
|
||||||
|
appCurrency = appCurrency,
|
||||||
|
account = account,
|
||||||
|
currency = currency,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
is CampaignsBottomSheetConfig.AlreadyActivated -> CampaignAlreadyActivatedBottomSheetComponent(
|
||||||
|
appComponentContext = context,
|
||||||
|
params = CampaignAlreadyActivatedModel.Params(
|
||||||
|
campaignType = config.campaignType,
|
||||||
|
appCurrency = config.appCurrency,
|
||||||
|
account = config.account,
|
||||||
|
currency = config.currency,
|
||||||
|
onDismiss = model::onDismiss,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,44 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.component
|
package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheet
|
import androidx.compose.runtime.State
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUM
|
import androidx.compose.ui.Modifier
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.icon
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.infoBlock
|
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.messageBottomSheetUM
|
import com.tangem.core.ui.ds2.button.Close
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.onClick
|
import com.tangem.core.ui.ds2.button.TangemButton
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.onDismiss
|
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
||||||
import com.tangem.core.ui.components.bottomsheets.message.primaryButton
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
|
||||||
import com.tangem.features.promobanners.impl.R
|
import com.tangem.features.promobanners.impl.R
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.ui.NotActiveCampaignMessageContent
|
||||||
|
|
||||||
internal class NotActiveCampaignBottomSheetComponent(
|
internal class NotActiveCampaignBottomSheetComponent(
|
||||||
private val onDismissRequest: () -> Unit,
|
private val onDismissRequest: () -> Unit,
|
||||||
) : ComposableBottomSheetComponent {
|
) : CampaignsModularComponent {
|
||||||
|
|
||||||
override fun dismiss() = onDismissRequest()
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun BottomSheet() {
|
override fun Title(bottomSheetState: State<BottomSheetState>) {
|
||||||
MessageBottomSheet(
|
TangemTopNavigation(
|
||||||
state = messageBottomSheetUM {
|
windowInsets = WindowInsets(0),
|
||||||
onDismiss(onDismissRequest)
|
blurBackground = false,
|
||||||
infoBlock {
|
endButton = { TangemButton.Close(onClick = onDismissRequest) },
|
||||||
icon(R.drawable.ic_alert_circle_24) {
|
)
|
||||||
type = MessageBottomSheetUM.Icon.Type.Warning
|
}
|
||||||
backgroundType = MessageBottomSheetUM.Icon.BackgroundType.SameAsTint
|
|
||||||
}
|
@Composable
|
||||||
title = stringReference("Campaign not active") // TODO localization
|
override fun Content(bottomSheetState: State<BottomSheetState>, contentPadding: PaddingValues, modifier: Modifier) {
|
||||||
body = stringReference("This campaign no longer exists or has expired.") // TODO localization
|
NotActiveCampaignMessageContent()
|
||||||
}
|
}
|
||||||
primaryButton {
|
|
||||||
text = resourceReference(R.string.common_close)
|
@Composable
|
||||||
onClick { closeBs() }
|
override fun Footer() {
|
||||||
}
|
PrimaryButton(
|
||||||
},
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onDismissRequest = onDismissRequest,
|
text = stringResourceSafe(R.string.common_close),
|
||||||
|
onClick = { onDismissRequest() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import com.tangem.features.promobanners.api.swapcashback.CampaignsComponent
|
||||||
import com.tangem.features.promobanners.impl.campaigns.component.DefaultCampaignsComponent
|
import com.tangem.features.promobanners.impl.campaigns.component.DefaultCampaignsComponent
|
||||||
import com.tangem.features.promobanners.impl.campaigns.deeplink.DefaultCampaignsDeepLinkHandler
|
import com.tangem.features.promobanners.impl.campaigns.deeplink.DefaultCampaignsDeepLinkHandler
|
||||||
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
|
import com.tangem.features.promobanners.impl.campaigns.model.ActivateCampaignsModel
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.model.CampaignAlreadyActivatedModel
|
||||||
import com.tangem.features.promobanners.impl.campaigns.model.CampaignsModel
|
import com.tangem.features.promobanners.impl.campaigns.model.CampaignsModel
|
||||||
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
|
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
|
||||||
import com.tangem.features.promobanners.impl.campaigns.service.DefaultCampaignsService
|
import com.tangem.features.promobanners.impl.campaigns.service.DefaultCampaignsService
|
||||||
|
|
@ -50,4 +51,9 @@ internal interface CampaignsModelModule {
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ClassKey(ActivateCampaignsModel::class)
|
@ClassKey(ActivateCampaignsModel::class)
|
||||||
fun bindCampaignActivateModel(model: ActivateCampaignsModel): Model
|
fun bindCampaignActivateModel(model: ActivateCampaignsModel): Model
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(CampaignAlreadyActivatedModel::class)
|
||||||
|
fun bindCampaignAlreadyActivatedModel(model: CampaignAlreadyActivatedModel): Model
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.entity
|
package com.tangem.features.promobanners.impl.campaigns.entity
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
|
||||||
|
|
@ -10,11 +12,39 @@ import com.tangem.core.ui.extensions.TextReference
|
||||||
* the footer shows "Select token"; once a token is chosen it shows the account block, the terms agreement
|
* the footer shows "Select token"; once a token is chosen it shows the account block, the terms agreement
|
||||||
* and the "Enroll" button. When [isChoosingToken] is `true` the token selector is shown on top of the
|
* and the "Enroll" button. When [isChoosingToken] is `true` the token selector is shown on top of the
|
||||||
* intro (as a stacked bottom sheet), not instead of it.
|
* intro (as a stacked bottom sheet), not instead of it.
|
||||||
|
*
|
||||||
|
* [selectedAccount] is shown above the token only in accounts (multi-account) mode — it names the account
|
||||||
|
* the asset was picked from. It is `null` in single-account mode or before a token is chosen.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Immutable
|
||||||
internal data class ActivateCampaignUM(
|
internal data class ActivateCampaignUM(
|
||||||
val campaignName: String,
|
|
||||||
val title: TextReference,
|
val title: TextReference,
|
||||||
val description: TextReference,
|
val description: TextReference,
|
||||||
val selectedToken: TokenItemState?,
|
val selectedToken: TokenItemState?,
|
||||||
|
val selectedAccount: SelectedAccountUM?,
|
||||||
val isChoosingToken: Boolean,
|
val isChoosingToken: Boolean,
|
||||||
|
val footerUM: FooterUM,
|
||||||
|
val onChooseTokenDismiss: () -> Unit,
|
||||||
|
val onLearnMoreClick: () -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
internal data class FooterUM(
|
||||||
|
val label: TextReference,
|
||||||
|
val onPrimaryButtonClick: () -> Unit,
|
||||||
|
val terms: TermsUM? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class TermsUM(
|
||||||
|
val text: TextReference,
|
||||||
|
val linkText: TextReference,
|
||||||
|
val onTermsClick: () -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
internal data class SelectedAccountUM(
|
||||||
|
val iconState: CurrencyIconState,
|
||||||
|
val name: TextReference,
|
||||||
)
|
)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.entity
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
internal data class CampaignAlreadyActivatedUM(
|
||||||
|
val selectedToken: TokenItemState,
|
||||||
|
val selectedAccount: SelectedAccountUM?,
|
||||||
|
)
|
||||||
|
|
@ -3,10 +3,13 @@ package com.tangem.features.promobanners.impl.campaigns.entity
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface CampaignType {
|
internal sealed class CampaignType {
|
||||||
|
|
||||||
val campaignId: String
|
abstract val campaignId: String
|
||||||
|
|
||||||
data class ReactivationCashback(override val campaignId: String) : CampaignType
|
@Serializable
|
||||||
data class WhaleSwapCashback(override val campaignId: String) : CampaignType
|
data class ReactivationCashback(override val campaignId: String) : CampaignType()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class WhaleSwapCashback(override val campaignId: String) : CampaignType()
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.entity
|
package com.tangem.features.promobanners.impl.campaigns.entity
|
||||||
|
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.account.Account
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
@ -17,4 +20,12 @@ internal sealed class CampaignsBottomSheetConfig {
|
||||||
data class Activate(
|
data class Activate(
|
||||||
val campaignType: CampaignType,
|
val campaignType: CampaignType,
|
||||||
) : CampaignsBottomSheetConfig()
|
) : CampaignsBottomSheetConfig()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AlreadyActivated(
|
||||||
|
val campaignType: CampaignType,
|
||||||
|
val appCurrency: AppCurrency,
|
||||||
|
val account: Account?,
|
||||||
|
val currency: CryptoCurrencyStatus,
|
||||||
|
) : CampaignsBottomSheetConfig()
|
||||||
}
|
}
|
||||||
|
|
@ -1,18 +1,29 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.model
|
package com.tangem.features.promobanners.impl.campaigns.model
|
||||||
|
|
||||||
|
import com.tangem.common.ui.account.AccountIconItemStateConverter
|
||||||
|
import com.tangem.common.ui.account.toUM
|
||||||
import com.tangem.common.ui.tokens.TokenItemStateConverter
|
import com.tangem.common.ui.tokens.TokenItemStateConverter
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
|
import com.tangem.core.ui.components.account.AccountIconSize
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
|
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
|
||||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.account.Account
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
|
||||||
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
|
||||||
import com.tangem.features.promobanners.impl.R
|
import com.tangem.features.promobanners.impl.R
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.ActivateCampaignUM
|
import com.tangem.features.promobanners.impl.campaigns.entity.ActivateCampaignUM
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.FooterUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.SelectedAccountUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.TermsUM
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.campaignName
|
import com.tangem.features.promobanners.impl.campaigns.entity.campaignName
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -21,6 +32,7 @@ import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ModelScoped
|
@ModelScoped
|
||||||
|
|
@ -29,11 +41,15 @@ internal class ActivateCampaignsModel @Inject constructor(
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
chooseTokenBridgeFactory: ChooseTokenBridge.Factory,
|
chooseTokenBridgeFactory: ChooseTokenBridge.Factory,
|
||||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
|
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||||
|
private val urlOpener: UrlOpener,
|
||||||
) : Model() {
|
) : Model() {
|
||||||
|
|
||||||
private val params = paramsContainer.require<Params>()
|
private val params = paramsContainer.require<Params>()
|
||||||
|
private val accountIconConverter = AccountIconItemStateConverter(size = AccountIconSize.ExtraSmall)
|
||||||
private var appCurrency: AppCurrency = AppCurrency.Default
|
private var appCurrency: AppCurrency = AppCurrency.Default
|
||||||
|
private var selectedAccount: Account? = null
|
||||||
|
private var selectedCurrency: CryptoCurrencyStatus? = null
|
||||||
|
|
||||||
val uiState: StateFlow<ActivateCampaignUM>
|
val uiState: StateFlow<ActivateCampaignUM>
|
||||||
field = MutableStateFlow(getInitialState())
|
field = MutableStateFlow(getInitialState())
|
||||||
|
|
@ -62,43 +78,104 @@ internal class ActivateCampaignsModel @Inject constructor(
|
||||||
.launchIn(modelScope)
|
.launchIn(modelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSelectTokenClick() {
|
private fun onSelectTokenClick() {
|
||||||
uiState.update { it.copy(isChoosingToken = true) }
|
uiState.update { it.copy(isChoosingToken = true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onChooseTokenDismiss() {
|
private fun onChooseTokenDismiss() {
|
||||||
uiState.update { it.copy(isChoosingToken = false) }
|
uiState.update { it.copy(isChoosingToken = false) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onEnrollClick() {
|
private fun onEnrollClick() {
|
||||||
// TODO([REDACTED_TASK_KEY]): call the real campaign enrollment use case with the chosen token before proceeding.
|
modelScope.launch {
|
||||||
params.onActivated(params.campaignType)
|
// TODO([REDACTED_TASK_KEY]): call the real campaign enrollment use case; its result decides the next sheet.
|
||||||
|
// Success -> the "enrolled" sheet; "already activated" error -> hand the chosen token/account
|
||||||
|
// over to the "already activated" sheet.
|
||||||
|
if (enrollInCampaign()) {
|
||||||
|
params.onActivated(params.campaignType)
|
||||||
|
} else {
|
||||||
|
selectedCurrency?.let {
|
||||||
|
params.onAlreadyActivated(params.campaignType, appCurrency, selectedAccount, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDismiss() = params.onDismiss()
|
@Suppress("FunctionOnlyReturningConstant") // TODO([REDACTED_TASK_KEY]): stub until the real enrollment use case exists.
|
||||||
|
private fun enrollInCampaign(): Boolean {
|
||||||
|
// TODO([REDACTED_TASK_KEY]): replace with the real enrollment use case call; `true` = enrolled, `false` = already active.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onTermsClick() {
|
||||||
|
urlOpener.openUrl(CAMPAIGN_TERMS_URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onLearnMoreClick() {
|
||||||
|
urlOpener.openUrl(CAMPAIGN_TERMS_URL)
|
||||||
|
}
|
||||||
|
|
||||||
private fun onTokenChosen(result: ChooseTokenResult) {
|
private fun onTokenChosen(result: ChooseTokenResult) {
|
||||||
val tokenItem = TokenItemStateConverter(appCurrency = appCurrency).convert(result.currency)
|
modelScope.launch {
|
||||||
|
val selectedAccountUM = if (isAccountsModeEnabledUseCase.invokeSync()) {
|
||||||
|
val account = result.account.account
|
||||||
|
selectedAccount = account
|
||||||
|
|
||||||
uiState.update { state ->
|
when (account) {
|
||||||
state.copy(
|
is Account.CryptoPortfolio -> SelectedAccountUM(
|
||||||
isChoosingToken = false,
|
iconState = accountIconConverter.convert(account),
|
||||||
selectedToken = tokenItem,
|
name = account.accountName.toUM().value,
|
||||||
)
|
)
|
||||||
|
is Account.Payment -> SelectedAccountUM(
|
||||||
|
iconState = CurrencyIconState.PaymentAccount(size = AccountIconSize.ExtraSmall),
|
||||||
|
name = account.accountName.toUM().value,
|
||||||
|
)
|
||||||
|
is Account.Virtual -> null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedCurrency = result.currency
|
||||||
|
val tokenItem = TokenItemStateConverter(appCurrency = appCurrency).convert(result.currency)
|
||||||
|
|
||||||
|
uiState.update { state ->
|
||||||
|
state.copy(
|
||||||
|
isChoosingToken = false,
|
||||||
|
selectedToken = tokenItem,
|
||||||
|
selectedAccount = selectedAccountUM,
|
||||||
|
footerUM = FooterUM(
|
||||||
|
label = stringReference("Enroll"),
|
||||||
|
onPrimaryButtonClick = ::onEnrollClick,
|
||||||
|
terms = TermsUM(
|
||||||
|
// TODO([REDACTED_TASK_KEY]): localize
|
||||||
|
text = stringReference("I agree with"),
|
||||||
|
linkText = stringReference("${params.campaignType.campaignName()} Terms"),
|
||||||
|
onTermsClick = ::onTermsClick,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInitialState(): ActivateCampaignUM {
|
private fun getInitialState(): ActivateCampaignUM {
|
||||||
return ActivateCampaignUM(
|
return ActivateCampaignUM(
|
||||||
campaignName = params.campaignType.campaignName(),
|
|
||||||
// TODO([REDACTED_TASK_KEY]): source real campaign copy.
|
// TODO([REDACTED_TASK_KEY]): source real campaign copy.
|
||||||
title = stringReference("Enroll in ${params.campaignType.campaignName()}"),
|
title = stringReference("Enroll in ${params.campaignType.campaignName()}"),
|
||||||
description = stringReference(
|
description = stringReference(
|
||||||
"Earn cashback on every swap from \$10K until the end of July.\n\n" +
|
"Earn cashback on every swap from \$10K until the end of July.\n\n" +
|
||||||
"Rates step up with size: 0.10% from \$10K, 0.20% from \$20K, 0.50% from \$100K.\n\n",
|
"Rates step up with size: 0.10% from \$10K, 0.20% from \$20K, 0.50% from \$100K.",
|
||||||
),
|
),
|
||||||
selectedToken = null,
|
selectedToken = null,
|
||||||
|
selectedAccount = null,
|
||||||
isChoosingToken = false,
|
isChoosingToken = false,
|
||||||
|
footerUM = FooterUM(
|
||||||
|
label = stringReference("Select token"),
|
||||||
|
onPrimaryButtonClick = ::onSelectTokenClick,
|
||||||
|
),
|
||||||
|
onChooseTokenDismiss = ::onChooseTokenDismiss,
|
||||||
|
onLearnMoreClick = ::onLearnMoreClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,5 +183,11 @@ internal class ActivateCampaignsModel @Inject constructor(
|
||||||
val campaignType: CampaignType,
|
val campaignType: CampaignType,
|
||||||
val onDismiss: () -> Unit,
|
val onDismiss: () -> Unit,
|
||||||
val onActivated: (CampaignType) -> Unit,
|
val onActivated: (CampaignType) -> Unit,
|
||||||
|
val onAlreadyActivated: (CampaignType, AppCurrency, Account?, CryptoCurrencyStatus) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
// TODO([REDACTED_TASK_KEY]): replace with the real campaign terms URL.
|
||||||
|
const val CAMPAIGN_TERMS_URL = "https://tangem.com/en/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.model
|
||||||
|
|
||||||
|
import com.tangem.common.ui.account.AccountIconItemStateConverter
|
||||||
|
import com.tangem.common.ui.account.toUM
|
||||||
|
import com.tangem.common.ui.tokens.TokenItemStateConverter
|
||||||
|
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.ui.components.account.AccountIconSize
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.account.Account
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignAlreadyActivatedUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.SelectedAccountUM
|
||||||
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thin model for the "campaign already activated" bottom sheet. The screen is read-only: it just renders
|
||||||
|
* the token/account the cashback is paid out to.
|
||||||
|
*
|
||||||
|
* The state is the selection the user made in the activate flow, handed over via [Params] when enrollment
|
||||||
|
* reports the campaign is already active. That selection is in-memory only (it carries non-serializable UI
|
||||||
|
* state), so after process death it is `null` and the model assembles a placeholder state instead
|
||||||
|
* (see [REDACTED_TASK_KEY]).
|
||||||
|
*/
|
||||||
|
@ModelScoped
|
||||||
|
internal class CampaignAlreadyActivatedModel @Inject constructor(
|
||||||
|
paramsContainer: ParamsContainer,
|
||||||
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
|
) : Model() {
|
||||||
|
|
||||||
|
private val params = paramsContainer.require<Params>()
|
||||||
|
private val accountIconConverter = AccountIconItemStateConverter(size = AccountIconSize.ExtraSmall)
|
||||||
|
|
||||||
|
val uiState: StateFlow<CampaignAlreadyActivatedUM>
|
||||||
|
field = MutableStateFlow(buildState())
|
||||||
|
|
||||||
|
private fun buildState(): CampaignAlreadyActivatedUM {
|
||||||
|
val selectedAccountUM = params.account?.let { account ->
|
||||||
|
when (account) {
|
||||||
|
is Account.CryptoPortfolio -> SelectedAccountUM(
|
||||||
|
iconState = accountIconConverter.convert(account),
|
||||||
|
name = account.accountName.toUM().value,
|
||||||
|
)
|
||||||
|
is Account.Payment -> SelectedAccountUM(
|
||||||
|
iconState = CurrencyIconState.PaymentAccount(size = AccountIconSize.ExtraSmall),
|
||||||
|
name = account.accountName.toUM().value,
|
||||||
|
)
|
||||||
|
is Account.Virtual -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val tokenItem = TokenItemStateConverter(appCurrency = params.appCurrency).convert(params.currency)
|
||||||
|
|
||||||
|
return CampaignAlreadyActivatedUM(
|
||||||
|
selectedToken = tokenItem,
|
||||||
|
selectedAccount = selectedAccountUM,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Params(
|
||||||
|
val campaignType: CampaignType,
|
||||||
|
val account: Account?,
|
||||||
|
val appCurrency: AppCurrency,
|
||||||
|
val currency: CryptoCurrencyStatus,
|
||||||
|
val onDismiss: () -> Unit,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,9 @@ import com.arkivanov.decompose.router.slot.activate
|
||||||
import com.arkivanov.decompose.router.slot.dismiss
|
import com.arkivanov.decompose.router.slot.dismiss
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.account.Account
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.features.promobanners.impl.campaigns.converters.CampaignIdConverter
|
import com.tangem.features.promobanners.impl.campaigns.converters.CampaignIdConverter
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignsBottomSheetConfig
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignsBottomSheetConfig
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignType
|
||||||
|
|
@ -57,4 +60,20 @@ internal class CampaignsModel @Inject constructor(
|
||||||
fun onActivated(campaignType: CampaignType) {
|
fun onActivated(campaignType: CampaignType) {
|
||||||
bottomSheetNavigation.activate(CampaignsBottomSheetConfig.Enrolled(campaignType))
|
bottomSheetNavigation.activate(CampaignsBottomSheetConfig.Enrolled(campaignType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onAlreadyActivated(
|
||||||
|
campaignType: CampaignType,
|
||||||
|
appCurrency: AppCurrency,
|
||||||
|
account: Account?,
|
||||||
|
currency: CryptoCurrencyStatus,
|
||||||
|
) {
|
||||||
|
bottomSheetNavigation.activate(
|
||||||
|
CampaignsBottomSheetConfig.AlreadyActivated(
|
||||||
|
campaignType = campaignType,
|
||||||
|
appCurrency = appCurrency,
|
||||||
|
account = account,
|
||||||
|
currency = currency,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.ui
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
|
||||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
|
||||||
import com.tangem.core.ui.ds2.button.Close
|
|
||||||
import com.tangem.core.ui.ds2.button.TangemButton
|
|
||||||
import com.tangem.core.ui.ds2.topnavigation.TangemTopNavigation
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.ActivateCampaignUM
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
internal fun ActivateCampaignContent(
|
|
||||||
state: ActivateCampaignUM,
|
|
||||||
onSelectTokenClick: () -> Unit,
|
|
||||||
onEnrollClick: () -> Unit,
|
|
||||||
onLearnMoreClick: () -> Unit,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
) {
|
|
||||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
|
||||||
config = TangemBottomSheetConfig(
|
|
||||||
isShown = true,
|
|
||||||
onDismissRequest = onDismiss,
|
|
||||||
content = TangemBottomSheetConfigContent.Empty,
|
|
||||||
),
|
|
||||||
containerColor = TangemTheme.colors.background.tertiary,
|
|
||||||
onBack = onDismiss,
|
|
||||||
title = {
|
|
||||||
TangemTopNavigation(
|
|
||||||
windowInsets = WindowInsets(0),
|
|
||||||
blurBackground = false,
|
|
||||||
endButton = {
|
|
||||||
TangemButton.Close(
|
|
||||||
onClick = onDismiss,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
content = {
|
|
||||||
ActivateCampaignContent(
|
|
||||||
state = state,
|
|
||||||
onSelectTokenClick = onSelectTokenClick,
|
|
||||||
onEnrollClick = onEnrollClick,
|
|
||||||
onLearnMoreClick = onLearnMoreClick,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.ui
|
package com.tangem.features.promobanners.impl.campaigns.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
|
@ -13,29 +14,26 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import com.tangem.core.ui.components.PrimaryButton
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.components.SpacerH12
|
import com.tangem.core.ui.components.SpacerH12
|
||||||
import com.tangem.core.ui.components.SpacerH16
|
|
||||||
import com.tangem.core.ui.components.SpacerH24
|
import com.tangem.core.ui.components.SpacerH24
|
||||||
|
import com.tangem.core.ui.components.SpacerH32
|
||||||
import com.tangem.core.ui.components.SpacerH8
|
import com.tangem.core.ui.components.SpacerH8
|
||||||
import com.tangem.core.ui.components.token.TokenItem
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
import com.tangem.core.ui.extensions.resolveReference
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
import com.tangem.features.promobanners.impl.R
|
import com.tangem.features.promobanners.impl.R
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.ActivateCampaignUM
|
import com.tangem.features.promobanners.impl.campaigns.entity.ActivateCampaignUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.SelectedAccountUM
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ActivateCampaignContent(
|
internal fun ActivateCampaignContent(um: ActivateCampaignUM) {
|
||||||
state: ActivateCampaignUM,
|
|
||||||
onSelectTokenClick: () -> Unit,
|
|
||||||
onEnrollClick: () -> Unit,
|
|
||||||
onLearnMoreClick: () -> Unit,
|
|
||||||
) {
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
.padding(horizontal = 16.dp),
|
||||||
.navigationBarsPadding(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
|
|
@ -43,93 +41,99 @@ internal fun ActivateCampaignContent(
|
||||||
painter = painterResource(R.drawable.ill_businessman_3d),
|
painter = painterResource(R.drawable.ill_businessman_3d),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(TangemTheme.dimens.size96)
|
.size(80.dp)
|
||||||
.clip(CircleShape),
|
.clip(CircleShape),
|
||||||
)
|
)
|
||||||
SpacerH16()
|
SpacerH32()
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = state.title.resolveReference(),
|
text = um.title.resolveReference(),
|
||||||
style = TangemTheme.typography.h3,
|
style = TangemTheme.typography3.heading.small,
|
||||||
color = TangemTheme.colors.text.primary1,
|
color = TangemTheme.colors3.text.primary,
|
||||||
textAlign = TextAlign.Start,
|
textAlign = TextAlign.Start,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH8()
|
SpacerH8()
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = state.description.resolveReference(),
|
text = um.description.resolveReference(),
|
||||||
style = TangemTheme.typography.body2,
|
style = TangemTheme.typography3.caption.medium,
|
||||||
color = TangemTheme.colors.text.secondary,
|
color = TangemTheme.colors3.text.secondary,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH12()
|
SpacerH12()
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
// TODO([REDACTED_TASK_KEY]): localize
|
// TODO([REDACTED_TASK_KEY]): localize
|
||||||
text = "Learn more",
|
text = "Learn more",
|
||||||
style = TangemTheme.typography.button,
|
style = TangemTheme.typography3.caption.medium,
|
||||||
color = TangemTheme.colors.text.accent,
|
color = TangemTheme.colors3.text.primary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(onClick = onLearnMoreClick),
|
.clickable(onClick = um.onLearnMoreClick),
|
||||||
)
|
)
|
||||||
|
|
||||||
val selectedToken = state.selectedToken
|
SelectedTokenContent(
|
||||||
if (selectedToken != null) {
|
selectedToken = um.selectedToken,
|
||||||
SpacerH24()
|
selectedAccount = um.selectedAccount,
|
||||||
Text(
|
|
||||||
text = "Select cashback account", // TODO([REDACTED_TASK_KEY]): localize
|
|
||||||
style = TangemTheme.typography.subtitle1,
|
|
||||||
color = TangemTheme.colors.text.primary1,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
)
|
|
||||||
SpacerH12()
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius16))
|
|
||||||
.background(TangemTheme.colors.background.primary)
|
|
||||||
.padding(vertical = TangemTheme.dimens.spacing12),
|
|
||||||
) {
|
|
||||||
TokenItem(state = selectedToken, isBalanceHidden = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SpacerH24()
|
|
||||||
|
|
||||||
Footer(
|
|
||||||
campaignName = state.campaignName,
|
|
||||||
hasSelectedToken = selectedToken != null,
|
|
||||||
onSelectTokenClick = onSelectTokenClick,
|
|
||||||
onEnrollClick = onEnrollClick,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SpacerH32()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Footer(
|
private fun SelectedTokenContent(selectedToken: TokenItemState?, selectedAccount: SelectedAccountUM?) {
|
||||||
campaignName: String,
|
if (selectedToken != null) {
|
||||||
hasSelectedToken: Boolean,
|
SpacerH24()
|
||||||
onSelectTokenClick: () -> Unit,
|
|
||||||
onEnrollClick: () -> Unit,
|
|
||||||
) {
|
|
||||||
if (hasSelectedToken) {
|
|
||||||
Text(
|
Text(
|
||||||
text = "I agree with $campaignName Terms", // TODO([REDACTED_TASK_KEY]): localize + clickable terms
|
text = "Select cashback account", // TODO([REDACTED_TASK_KEY]): localize
|
||||||
style = TangemTheme.typography.caption2,
|
style = TangemTheme.typography.subtitle1,
|
||||||
color = TangemTheme.colors.text.secondary,
|
color = TangemTheme.colors.text.primary1,
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
SpacerH12()
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimaryButton(
|
SpacerH12()
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
text = if (hasSelectedToken) {
|
PromoCampaignTokenItem(
|
||||||
"Enroll" // TODO([REDACTED_TASK_KEY]): localize
|
modifier = Modifier
|
||||||
} else {
|
.fillMaxWidth()
|
||||||
"Select token" // TODO([REDACTED_TASK_KEY]): localize
|
.clip(RoundedCornerShape(24.dp))
|
||||||
},
|
.background(TangemTheme.colors.background.primary),
|
||||||
onClick = if (hasSelectedToken) onEnrollClick else onSelectTokenClick,
|
selectedToken = selectedToken,
|
||||||
)
|
selectedAccount = selectedAccount,
|
||||||
SpacerH16()
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region Preview
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_ActivateCampaignContent_WithToken() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
Box(modifier = Modifier.background(TangemTheme.colors3.bg.primary)) {
|
||||||
|
ActivateCampaignContent(um = CampaignPreviewData.activateCampaign)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_ActivateCampaignContent_NoToken() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
Box(modifier = Modifier.background(TangemTheme.colors3.bg.primary)) {
|
||||||
|
ActivateCampaignContent(
|
||||||
|
um = CampaignPreviewData.activateCampaign.copy(
|
||||||
|
selectedToken = null,
|
||||||
|
selectedAccount = null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.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.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.LinkAnnotation
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.withLink
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
|
import com.tangem.core.ui.components.SpacerH12
|
||||||
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.FooterUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.TermsUM
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ActivateCampaignFooter(footerUM: FooterUM, modifier: Modifier = Modifier) {
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
val terms = footerUM.terms
|
||||||
|
|
||||||
|
if (terms != null) {
|
||||||
|
Text(
|
||||||
|
text = termsAnnotatedString(terms),
|
||||||
|
style = TangemTheme.typography.caption2,
|
||||||
|
color = TangemTheme.colors.text.secondary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH12()
|
||||||
|
|
||||||
|
PrimaryButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = footerUM.label.resolveReference(),
|
||||||
|
onClick = footerUM.onPrimaryButtonClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun termsAnnotatedString(terms: TermsUM) = buildAnnotatedString {
|
||||||
|
val startText = terms.text.resolveReference()
|
||||||
|
val linkText = terms.linkText.resolveReference()
|
||||||
|
|
||||||
|
append(startText)
|
||||||
|
append(" ")
|
||||||
|
withLink(
|
||||||
|
link = LinkAnnotation.Clickable(
|
||||||
|
tag = "CAMPAIGN_TERMS",
|
||||||
|
linkInteractionListener = { terms.onTermsClick() },
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
withStyle(
|
||||||
|
SpanStyle(
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
textDecoration = TextDecoration.None,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
append(linkText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Preview
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_ActivateCampaignFooter_WithTerms() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
ActivateCampaignFooter(
|
||||||
|
footerUM = CampaignPreviewData.footer,
|
||||||
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors3.bg.primary)
|
||||||
|
.padding(16.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_ActivateCampaignFooter_NoTerms() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
ActivateCampaignFooter(
|
||||||
|
footerUM = CampaignPreviewData.footer.copy(terms = null),
|
||||||
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors3.bg.primary)
|
||||||
|
.padding(16.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
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.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.ui.components.SpacerH12
|
||||||
|
import com.tangem.core.ui.components.SpacerH24
|
||||||
|
import com.tangem.core.ui.components.SpacerH32
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_info_24
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignAlreadyActivatedUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.SelectedAccountUM
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ActivateCampaignContent(um: CampaignAlreadyActivatedUM) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(TangemTheme.colors3.bg.status.infoSubtle),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
imageVector = Icons.ic_info_24,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = TangemTheme.colors3.icon.status.info,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH32()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "You’re already enrolled in Whale Swap Cashback", // TODO localization
|
||||||
|
style = TangemTheme.typography3.heading.small,
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH12()
|
||||||
|
|
||||||
|
SelectedTokenContent(
|
||||||
|
selectedToken = um.selectedToken,
|
||||||
|
selectedAccount = um.selectedAccount,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH32()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SelectedTokenContent(selectedToken: TokenItemState, selectedAccount: SelectedAccountUM?) {
|
||||||
|
SpacerH24()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Eligible cashback will be distributed to:", // TODO([REDACTED_TASK_KEY]): localize
|
||||||
|
style = TangemTheme.typography.subtitle1,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH12()
|
||||||
|
|
||||||
|
PromoCampaignTokenItem(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
selectedToken = selectedToken,
|
||||||
|
selectedAccount = selectedAccount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Preview
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_AlreadyActivatedCampaignContent() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
Box(modifier = Modifier.background(TangemTheme.colors3.bg.primary)) {
|
||||||
|
ActivateCampaignContent(um = CampaignPreviewData.alreadyActivated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
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.foundation.shape.CircleShape
|
||||||
|
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.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.ui.components.SpacerH
|
||||||
|
import com.tangem.core.ui.components.SpacerH32
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_success_24
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CampaignEnrolledMessageContent(message: TextReference, modifier: Modifier = Modifier) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(TangemTheme.colors3.bg.status.successSubtle),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
imageVector = Icons.ic_success_24,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = TangemTheme.colors3.icon.status.success,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH32()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = message.resolveReference(),
|
||||||
|
style = TangemTheme.typography3.heading.small,
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(48.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.ui
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.ActivateCampaignUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.CampaignAlreadyActivatedUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.FooterUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.SelectedAccountUM
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.TermsUM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared preview fixtures for the campaign UI `@Preview`s. Not used in production code.
|
||||||
|
*/
|
||||||
|
internal object CampaignPreviewData {
|
||||||
|
|
||||||
|
val tokenItem: TokenItemState.Content = TokenItemState.Content(
|
||||||
|
id = "preview-token",
|
||||||
|
iconState = CurrencyIconState.CoinIcon(
|
||||||
|
url = null,
|
||||||
|
fallbackResId = com.tangem.core.ui.R.drawable.img_polygon_22,
|
||||||
|
isGrayscale = false,
|
||||||
|
shouldShowCustomBadge = false,
|
||||||
|
),
|
||||||
|
titleState = TokenItemState.TitleState.Content(text = stringReference("Polygon")),
|
||||||
|
subtitleState = TokenItemState.SubtitleState.TextContent(value = stringReference("MATIC")),
|
||||||
|
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $"),
|
||||||
|
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,412 MATIC"),
|
||||||
|
onItemClick = {},
|
||||||
|
onItemLongClick = {},
|
||||||
|
)
|
||||||
|
|
||||||
|
val selectedAccount: SelectedAccountUM = SelectedAccountUM(
|
||||||
|
iconState = CurrencyIconState.CryptoPortfolio.Icon(
|
||||||
|
resId = com.tangem.core.ui.R.drawable.ic_rounded_star_24,
|
||||||
|
color = Color(color = 0xFF0099FF),
|
||||||
|
isGrayscale = false,
|
||||||
|
),
|
||||||
|
name = stringReference("Main account"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val footer: FooterUM = FooterUM(
|
||||||
|
label = stringReference("Enroll"),
|
||||||
|
onPrimaryButtonClick = {},
|
||||||
|
terms = TermsUM(
|
||||||
|
text = stringReference("By enrolling you agree to the"),
|
||||||
|
linkText = stringReference("Terms & Conditions"),
|
||||||
|
onTermsClick = {},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val activateCampaign: ActivateCampaignUM = ActivateCampaignUM(
|
||||||
|
title = stringReference("Whale Swap Cashback"),
|
||||||
|
description = stringReference(
|
||||||
|
"Get cashback on every swap. Pick a token and the account where your rewards will be paid out.",
|
||||||
|
),
|
||||||
|
selectedToken = tokenItem,
|
||||||
|
selectedAccount = selectedAccount,
|
||||||
|
isChoosingToken = false,
|
||||||
|
footerUM = footer,
|
||||||
|
onChooseTokenDismiss = {},
|
||||||
|
onLearnMoreClick = {},
|
||||||
|
)
|
||||||
|
|
||||||
|
val alreadyActivated: CampaignAlreadyActivatedUM = CampaignAlreadyActivatedUM(
|
||||||
|
selectedToken = tokenItem,
|
||||||
|
selectedAccount = selectedAccount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
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.foundation.shape.CircleShape
|
||||||
|
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.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.ui.components.SpacerH
|
||||||
|
import com.tangem.core.ui.components.SpacerH32
|
||||||
|
import com.tangem.core.ui.components.SpacerH8
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.generated.icons.Icons
|
||||||
|
import com.tangem.core.ui.res.generated.icons.ic_warning_24
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NotActiveCampaignMessageContent(modifier: Modifier = Modifier) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(TangemTheme.colors3.bg.status.warningSubtle),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
imageVector = Icons.ic_warning_24,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = TangemTheme.colors3.icon.status.warning,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH32()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = " Campaign not active", // TODO localization
|
||||||
|
style = TangemTheme.typography3.heading.small,
|
||||||
|
color = TangemTheme.colors3.text.primary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH8()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "This campaign no longer exists or has expired", // TODO localization
|
||||||
|
style = TangemTheme.typography3.subheading.medium,
|
||||||
|
color = TangemTheme.colors3.text.secondary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(48.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
package com.tangem.features.promobanners.impl.campaigns.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
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.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.core.ui.components.SpacerH8
|
||||||
|
import com.tangem.core.ui.components.SpacerW4
|
||||||
|
import com.tangem.core.ui.components.account.AccountCharIcon
|
||||||
|
import com.tangem.core.ui.components.account.AccountIconSize
|
||||||
|
import com.tangem.core.ui.components.account.AccountResIcon
|
||||||
|
import com.tangem.core.ui.components.account.PaymentAccountIcon
|
||||||
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.core.ui.components.token.TokenItem
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||||
|
import com.tangem.features.promobanners.impl.campaigns.entity.SelectedAccountUM
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun PromoCampaignTokenItem(
|
||||||
|
selectedToken: TokenItemState,
|
||||||
|
selectedAccount: SelectedAccountUM?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(modifier = modifier) {
|
||||||
|
if (selectedAccount != null) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
when (val icon = selectedAccount.iconState) {
|
||||||
|
is CurrencyIconState.PaymentAccount -> PaymentAccountIcon(size = icon.size)
|
||||||
|
is CurrencyIconState.CryptoPortfolio.Icon -> AccountResIcon(
|
||||||
|
resId = icon.resId,
|
||||||
|
color = icon.color,
|
||||||
|
size = AccountIconSize.ExtraSmall,
|
||||||
|
)
|
||||||
|
is CurrencyIconState.CryptoPortfolio.Letter -> AccountCharIcon(
|
||||||
|
char = icon.char.resolveReference().first(),
|
||||||
|
color = icon.color,
|
||||||
|
size = AccountIconSize.ExtraSmall,
|
||||||
|
)
|
||||||
|
is CurrencyIconState.CoinIcon,
|
||||||
|
is CurrencyIconState.CustomTokenIcon,
|
||||||
|
is CurrencyIconState.Empty,
|
||||||
|
is CurrencyIconState.FiatIcon,
|
||||||
|
CurrencyIconState.Loading,
|
||||||
|
CurrencyIconState.Locked,
|
||||||
|
is CurrencyIconState.TokenIcon,
|
||||||
|
-> Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerW4()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 2.dp)
|
||||||
|
.alignByBaseline(),
|
||||||
|
text = selectedAccount.name.resolveReference(),
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
style = TangemTheme.typography.caption1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpacerH8()
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenItem(
|
||||||
|
state = selectedToken,
|
||||||
|
isBalanceHidden = false,
|
||||||
|
itemPaddingValues = PaddingValues(horizontal = 16.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Preview
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_PromoCampaignTokenItem_WithAccount() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
PromoCampaignTokenItem(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors3.bg.primary)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(24.dp))
|
||||||
|
.background(TangemTheme.colors.background.primary),
|
||||||
|
selectedToken = CampaignPreviewData.tokenItem,
|
||||||
|
selectedAccount = CampaignPreviewData.selectedAccount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
private fun Preview_PromoCampaignTokenItem_NoAccount() {
|
||||||
|
TangemThemePreviewRedesign {
|
||||||
|
PromoCampaignTokenItem(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors3.bg.primary)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(24.dp))
|
||||||
|
.background(TangemTheme.colors.background.primary),
|
||||||
|
selectedToken = CampaignPreviewData.tokenItem,
|
||||||
|
selectedAccount = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
Loading…
Add table
Add a link
Reference in a new issue