Updated on 2026-08-14
This commit is contained in:
parent
3e900b5d5b
commit
33efe2ae52
12 changed files with 56 additions and 101 deletions
|
|
@ -323,7 +323,9 @@ fun BoxScope.FooterOverlay(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.align(Alignment.BottomCenter),
|
.align(Alignment.BottomCenter),
|
||||||
) {
|
) {
|
||||||
if (gradientHeight > 0.dp) {
|
val isGradientDisplayed = gradientHeight > 0.dp
|
||||||
|
|
||||||
|
if (isGradientDisplayed) {
|
||||||
Fade(
|
Fade(
|
||||||
backgroundColor = fadeMax,
|
backgroundColor = fadeMax,
|
||||||
height = gradientHeight,
|
height = gradientHeight,
|
||||||
|
|
@ -333,7 +335,7 @@ fun BoxScope.FooterOverlay(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(measuredFooterHeight ?: 0.dp)
|
.height(measuredFooterHeight ?: 0.dp)
|
||||||
.background(fadeMax),
|
.background(if (isGradientDisplayed) fadeMax else Color.Transparent),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
import com.tangem.core.ui.components.*
|
import com.tangem.core.ui.components.*
|
||||||
|
|
@ -39,9 +38,6 @@ import com.tangem.core.ui.res.TangemThemePreview
|
||||||
import com.tangem.core.ui.utils.WindowInsetsZero
|
import com.tangem.core.ui.utils.WindowInsetsZero
|
||||||
import com.tangem.core.ui.utils.toPx
|
import com.tangem.core.ui.utils.toPx
|
||||||
|
|
||||||
/** Default reserved height for the [TangemModalBottomSheetWithFooter] footer slot. */
|
|
||||||
val DEFAULT_FOOTER_HEIGHT: Dp = 80.dp
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modal bottom sheet with [content], [footer] and optional [title].
|
* Modal bottom sheet with [content], [footer] and optional [title].
|
||||||
*
|
*
|
||||||
|
|
@ -54,12 +50,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> TangemModalBottomSheetWi
|
||||||
config: TangemBottomSheetConfig,
|
config: TangemBottomSheetConfig,
|
||||||
containerColor: Color = TangemTheme.colors.background.primary,
|
containerColor: Color = TangemTheme.colors.background.primary,
|
||||||
skipPartiallyExpanded: Boolean = true,
|
skipPartiallyExpanded: Boolean = true,
|
||||||
// FIXME([REDACTED_TASK_KEY]): temp workaround
|
|
||||||
// The footer slot reserves a fixed [DEFAULT_FOOTER_HEIGHT];
|
|
||||||
// callers whose footer differs must pass the real height explicitly. Exposed as an opt-in
|
|
||||||
// parameter so existing usages keep the previous behavior and nothing else is affected.
|
|
||||||
// Rework so the sheet measures the actual footer height internally and drops this parameter.
|
|
||||||
footerHeight: Dp = DEFAULT_FOOTER_HEIGHT,
|
|
||||||
noinline onBack: (() -> Unit)? = null,
|
noinline onBack: (() -> Unit)? = null,
|
||||||
crossinline title: @Composable BoxScope.(T) -> Unit = {},
|
crossinline title: @Composable BoxScope.(T) -> Unit = {},
|
||||||
crossinline content: @Composable (T) -> Unit,
|
crossinline content: @Composable (T) -> Unit,
|
||||||
|
|
@ -75,7 +65,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> TangemModalBottomSheetWi
|
||||||
content = content,
|
content = content,
|
||||||
footer = footer,
|
footer = footer,
|
||||||
skipPartiallyExpanded = skipPartiallyExpanded,
|
skipPartiallyExpanded = skipPartiallyExpanded,
|
||||||
footerHeight = footerHeight,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
DefaultModalBottomSheetWithFooter<T>(
|
DefaultModalBottomSheetWithFooter<T>(
|
||||||
|
|
@ -86,7 +75,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> TangemModalBottomSheetWi
|
||||||
footer = footer,
|
footer = footer,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
skipPartiallyExpanded = skipPartiallyExpanded,
|
skipPartiallyExpanded = skipPartiallyExpanded,
|
||||||
footerHeight = footerHeight,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +85,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> DefaultModalBottomSheetW
|
||||||
config: TangemBottomSheetConfig,
|
config: TangemBottomSheetConfig,
|
||||||
containerColor: Color,
|
containerColor: Color,
|
||||||
skipPartiallyExpanded: Boolean = true,
|
skipPartiallyExpanded: Boolean = true,
|
||||||
footerHeight: Dp = DEFAULT_FOOTER_HEIGHT,
|
|
||||||
noinline onBack: (() -> Unit)? = null,
|
noinline onBack: (() -> Unit)? = null,
|
||||||
crossinline title: @Composable BoxScope.(T) -> Unit,
|
crossinline title: @Composable BoxScope.(T) -> Unit,
|
||||||
crossinline content: @Composable (T) -> Unit,
|
crossinline content: @Composable (T) -> Unit,
|
||||||
|
|
@ -130,7 +117,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> DefaultModalBottomSheetW
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
content = content,
|
content = content,
|
||||||
footer = footer,
|
footer = footer,
|
||||||
footerHeight = footerHeight,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +135,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> PreviewModalBottomSheetW
|
||||||
config: TangemBottomSheetConfig,
|
config: TangemBottomSheetConfig,
|
||||||
containerColor: Color,
|
containerColor: Color,
|
||||||
skipPartiallyExpanded: Boolean = true,
|
skipPartiallyExpanded: Boolean = true,
|
||||||
footerHeight: Dp = DEFAULT_FOOTER_HEIGHT,
|
|
||||||
crossinline title: @Composable BoxScope.(T) -> Unit,
|
crossinline title: @Composable BoxScope.(T) -> Unit,
|
||||||
crossinline content: @Composable (T) -> Unit,
|
crossinline content: @Composable (T) -> Unit,
|
||||||
noinline footer: @Composable (BoxScope.(T) -> Unit)?,
|
noinline footer: @Composable (BoxScope.(T) -> Unit)?,
|
||||||
|
|
@ -165,7 +150,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> PreviewModalBottomSheetW
|
||||||
title = title,
|
title = title,
|
||||||
content = content,
|
content = content,
|
||||||
footer = footer,
|
footer = footer,
|
||||||
footerHeight = footerHeight,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +161,6 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicModalBottomSheetWit
|
||||||
sheetState: TangemSheetState,
|
sheetState: TangemSheetState,
|
||||||
containerColor: Color,
|
containerColor: Color,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
footerHeight: Dp = DEFAULT_FOOTER_HEIGHT,
|
|
||||||
noinline onBack: (() -> Unit)? = null,
|
noinline onBack: (() -> Unit)? = null,
|
||||||
crossinline title: @Composable BoxScope.(T) -> Unit,
|
crossinline title: @Composable BoxScope.(T) -> Unit,
|
||||||
crossinline content: @Composable (T) -> Unit,
|
crossinline content: @Composable (T) -> Unit,
|
||||||
|
|
@ -195,8 +178,7 @@ inline fun <reified T : TangemBottomSheetConfigContent> BasicModalBottomSheetWit
|
||||||
|
|
||||||
val isKeyboardOpen by rememberIsKeyboardVisible()
|
val isKeyboardOpen by rememberIsKeyboardVisible()
|
||||||
val buttonHeight by animateDpAsState(
|
val buttonHeight by animateDpAsState(
|
||||||
targetValue = if (footer != null) footerHeight else 0.dp,
|
targetValue = if (footer != null) 80.dp else 0.dp,
|
||||||
label = "FooterHeight",
|
|
||||||
)
|
)
|
||||||
// Offset calculation for keyboard scroll adjustment:
|
// Offset calculation for keyboard scroll adjustment:
|
||||||
// 1) Button height (footer)
|
// 1) Button height (footer)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
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
|
||||||
|
|
@ -29,7 +28,6 @@ internal class ActivateCampaignBottomSheetComponent(
|
||||||
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
chooseTokenComponentFactory: ChooseTokenComponent.Factory,
|
||||||
private val params: Params,
|
private val params: Params,
|
||||||
val onDismiss: () -> Unit,
|
val onDismiss: () -> Unit,
|
||||||
val onFooterExtraHeightReady: (Dp) -> Unit,
|
|
||||||
) : ComposableModularContentComponent, AppComponentContext by appComponentContext {
|
) : ComposableModularContentComponent, AppComponentContext by appComponentContext {
|
||||||
|
|
||||||
private val model: ActivateCampaignsModel = getOrCreateModel(params)
|
private val model: ActivateCampaignsModel = getOrCreateModel(params)
|
||||||
|
|
@ -65,7 +63,6 @@ internal class ActivateCampaignBottomSheetComponent(
|
||||||
|
|
||||||
ActivateCampaignFooter(
|
ActivateCampaignFooter(
|
||||||
footerUM = state.footerUM,
|
footerUM = state.footerUM,
|
||||||
onFooterTextHeightReady = onFooterExtraHeightReady,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,31 @@ package com.tangem.features.promobanners.impl.campaigns.component
|
||||||
|
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
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.components.SpacerH32
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.LocalBottomSheetContentScrollable
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.LocalTangemBottomSheetContentBottomInset
|
||||||
|
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.modal.DEFAULT_FOOTER_HEIGHT
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType
|
||||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter
|
|
||||||
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||||
import com.tangem.core.ui.extensions.rememberLastNonNull
|
import com.tangem.core.ui.extensions.rememberLastNonNull
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
@ -52,31 +60,44 @@ internal class DefaultCampaignsComponent @AssistedInject constructor(
|
||||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||||
val activeChild = bottomSheet.child?.instance
|
val activeChild = bottomSheet.child?.instance
|
||||||
val displayedChild = rememberLastNonNull(activeChild)
|
val displayedChild = rememberLastNonNull(activeChild)
|
||||||
val footerExtraHeight by model.footerExtraHeightState.collectAsStateWithLifecycle()
|
|
||||||
|
|
||||||
TangemModalBottomSheetWithFooter<TangemBottomSheetConfigContent.Empty>(
|
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||||
config = TangemBottomSheetConfig(
|
config = TangemBottomSheetConfig(
|
||||||
isShown = activeChild != null,
|
isShown = activeChild != null,
|
||||||
onDismissRequest = model::onDismiss,
|
onDismissRequest = model::onDismiss,
|
||||||
content = TangemBottomSheetConfigContent.Empty,
|
content = TangemBottomSheetConfigContent.Empty,
|
||||||
),
|
),
|
||||||
containerColor = TangemTheme.colors3.bg.primary,
|
containerColor = TangemTheme.colors3.bg.primary,
|
||||||
footerHeight = DEFAULT_FOOTER_HEIGHT + footerExtraHeight,
|
type = TangemBottomSheetType.Modal,
|
||||||
onBack = model::onDismiss,
|
onBack = model::onDismiss,
|
||||||
title = {
|
title = {
|
||||||
displayedChild?.Title()
|
displayedChild?.Title()
|
||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
Box(modifier = Modifier.animateContentSize()) {
|
val bottomInset = LocalTangemBottomSheetContentBottomInset.current
|
||||||
displayedChild?.Content(modifier = Modifier)
|
val bottomReserve = if (bottomInset > 0.dp) bottomInset else 16.dp
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
val scrollableSignal = LocalBottomSheetContentScrollable.current
|
||||||
|
|
||||||
|
if (scrollableSignal != null) {
|
||||||
|
LaunchedEffect(scrollState) {
|
||||||
|
snapshotFlow { scrollState.canScrollForward || scrollState.canScrollBackward }
|
||||||
|
.collect { canScroll -> scrollableSignal.value = canScroll }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(modifier = Modifier.verticalScroll(state = scrollState)) {
|
||||||
|
Box(modifier = Modifier.animateContentSize()) {
|
||||||
|
displayedChild?.Content(modifier = Modifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollableSignal?.value != true) SpacerH32()
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(bottomReserve))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
footer = {
|
footer = {
|
||||||
Box(
|
Box(modifier = Modifier.padding(12.dp)) {
|
||||||
modifier = Modifier
|
|
||||||
.navigationBarsPadding()
|
|
||||||
.padding(12.dp),
|
|
||||||
) {
|
|
||||||
displayedChild?.Footer()
|
displayedChild?.Footer()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -102,7 +123,6 @@ internal class DefaultCampaignsComponent @AssistedInject constructor(
|
||||||
appComponentContext = context,
|
appComponentContext = context,
|
||||||
chooseTokenComponentFactory = chooseTokenComponentFactory,
|
chooseTokenComponentFactory = chooseTokenComponentFactory,
|
||||||
onDismiss = model::onDismiss,
|
onDismiss = model::onDismiss,
|
||||||
onFooterExtraHeightReady = model::onFooterExtraHeightReady,
|
|
||||||
params = ActivateCampaignBottomSheetComponent.Params(
|
params = ActivateCampaignBottomSheetComponent.Params(
|
||||||
campaignType = config.campaignType,
|
campaignType = config.campaignType,
|
||||||
userWalletId = config.userWalletId,
|
userWalletId = config.userWalletId,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.core.ui.components.account.AccountIconSize
|
import com.tangem.core.ui.components.account.AccountIconSize
|
||||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||||
|
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.wrappedList
|
import com.tangem.core.ui.extensions.wrappedList
|
||||||
import com.tangem.core.ui.message.ToastMessage
|
import com.tangem.core.ui.message.ToastMessage
|
||||||
|
|
@ -219,7 +220,17 @@ internal class ActivateCampaignsModel @Inject constructor(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val tokenItem = TokenItemStateConverter(appCurrency = appCurrency).convert(result.currency)
|
val tokenItem = TokenItemStateConverter(
|
||||||
|
appCurrency = appCurrency,
|
||||||
|
subtitleStateProvider = { status ->
|
||||||
|
TokenItemState.SubtitleState.TextContent(
|
||||||
|
value = resourceReference(
|
||||||
|
R.string.domain_receive_assets_onboarding_network_name,
|
||||||
|
wrappedList(status.currency.network.name),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
).convert(result.currency)
|
||||||
|
|
||||||
uiState.update { state ->
|
uiState.update { state ->
|
||||||
state.copy(
|
state.copy(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.model
|
package com.tangem.features.promobanners.impl.campaigns.model
|
||||||
|
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||||
import com.arkivanov.decompose.router.slot.activate
|
import com.arkivanov.decompose.router.slot.activate
|
||||||
import com.arkivanov.decompose.router.slot.dismiss
|
import com.arkivanov.decompose.router.slot.dismiss
|
||||||
|
|
@ -24,8 +22,6 @@ import com.tangem.features.promobanners.impl.campaigns.entity.toPromoCampaignId
|
||||||
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
|
import com.tangem.features.promobanners.impl.campaigns.service.CampaignsService
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import com.tangem.utils.logging.TangemLogger
|
import com.tangem.utils.logging.TangemLogger
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -43,9 +39,6 @@ internal class CampaignsModel @Inject constructor(
|
||||||
|
|
||||||
val bottomSheetNavigation: SlotNavigation<CampaignsBottomSheetConfig> = SlotNavigation()
|
val bottomSheetNavigation: SlotNavigation<CampaignsBottomSheetConfig> = SlotNavigation()
|
||||||
|
|
||||||
val footerExtraHeightState: StateFlow<Dp>
|
|
||||||
field = MutableStateFlow(0.dp)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
campaignsService.campaignFlow
|
campaignsService.campaignFlow
|
||||||
.onEach { request ->
|
.onEach { request ->
|
||||||
|
|
@ -89,22 +82,16 @@ internal class CampaignsModel @Inject constructor(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
fun onFooterExtraHeightReady(height: Dp) {
|
|
||||||
footerExtraHeightState.value = height
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onDismiss() {
|
fun onDismiss() {
|
||||||
bottomSheetNavigation.dismiss()
|
bottomSheetNavigation.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onActivated(campaignType: CampaignType) {
|
fun onActivated(campaignType: CampaignType) {
|
||||||
footerExtraHeightState.value = 0.dp
|
|
||||||
bottomSheetNavigation.activate(CampaignsBottomSheetConfig.Enrolled(campaignType))
|
bottomSheetNavigation.activate(CampaignsBottomSheetConfig.Enrolled(campaignType))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onAlreadyActivated(campaignType: CampaignType) {
|
fun onAlreadyActivated(campaignType: CampaignType) {
|
||||||
analyticsEventHandler.send(PromoCampaignsAnalyticsEvent.AlreadyEnrolledScreenOpened())
|
analyticsEventHandler.send(PromoCampaignsAnalyticsEvent.AlreadyEnrolledScreenOpened())
|
||||||
footerExtraHeightState.value = 0.dp
|
|
||||||
bottomSheetNavigation.activate(CampaignsBottomSheetConfig.AlreadyActivated(campaignType = campaignType))
|
bottomSheetNavigation.activate(CampaignsBottomSheetConfig.AlreadyActivated(campaignType = campaignType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -78,8 +78,6 @@ internal fun ActivateCampaignContent(um: ActivateCampaignUM, modifier: Modifier
|
||||||
selectedAccount = um.selectedAccount,
|
selectedAccount = um.selectedAccount,
|
||||||
onChooseTokenClick = um.onChooseTokenClick,
|
onChooseTokenClick = um.onChooseTokenClick,
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH32()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.text.LinkAnnotation
|
import androidx.compose.ui.text.LinkAnnotation
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
|
@ -18,7 +16,6 @@ import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.text.withLink
|
import androidx.compose.ui.text.withLink
|
||||||
import androidx.compose.ui.text.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.components.PrimaryButton
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
import com.tangem.core.ui.components.SpacerH12
|
import com.tangem.core.ui.components.SpacerH12
|
||||||
|
|
@ -29,28 +26,17 @@ import com.tangem.features.promobanners.impl.campaigns.entity.FooterUM
|
||||||
import com.tangem.features.promobanners.impl.campaigns.entity.TermsUM
|
import com.tangem.features.promobanners.impl.campaigns.entity.TermsUM
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ActivateCampaignFooter(
|
internal fun ActivateCampaignFooter(footerUM: FooterUM, modifier: Modifier = Modifier) {
|
||||||
footerUM: FooterUM,
|
|
||||||
onFooterTextHeightReady: (Dp) -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
val terms = footerUM.terms
|
val terms = footerUM.terms
|
||||||
|
|
||||||
if (terms != null) {
|
if (terms != null) {
|
||||||
val density = LocalDensity.current
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = termsAnnotatedString(terms),
|
text = termsAnnotatedString(terms),
|
||||||
style = TangemTheme.typography.caption2,
|
style = TangemTheme.typography.caption2,
|
||||||
color = TangemTheme.colors.text.secondary,
|
color = TangemTheme.colors.text.secondary,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth(),
|
||||||
.fillMaxWidth()
|
|
||||||
.onSizeChanged {
|
|
||||||
val termsBlockHeight = with(density) { it.height.toDp() } + 12.dp
|
|
||||||
onFooterTextHeightReady.invoke(termsBlockHeight)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH12()
|
SpacerH12()
|
||||||
|
|
@ -99,7 +85,6 @@ private fun Preview_ActivateCampaignFooter_WithTerms() {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(TangemTheme.colors3.bg.primary)
|
.background(TangemTheme.colors3.bg.primary)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
onFooterTextHeightReady = {},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +99,6 @@ private fun Preview_ActivateCampaignFooter_NoTerms() {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(TangemTheme.colors3.bg.primary)
|
.background(TangemTheme.colors3.bg.primary)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
onFooterTextHeightReady = {},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,6 @@ internal fun AlreadyActivatedCampaignContent(message: TextReference, modifier: M
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH32()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,6 @@ fun CampaignEnrolledMessageContent(message: TextReference, modifier: Modifier =
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH32()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,5 @@ fun NotActiveCampaignMessageContent(modifier: Modifier = Modifier) {
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
|
|
||||||
SpacerH32()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package com.tangem.features.promobanners.impl.campaigns.model
|
package com.tangem.features.promobanners.impl.campaigns.model
|
||||||
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
@ -108,11 +106,10 @@ internal class CampaignsModelTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN footer height set WHEN onAlreadyActivated THEN analytics sent and height reset`() = runTest {
|
fun `WHEN onAlreadyActivated THEN analytics sent`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
val model = createModel(campaignFlow = emptyFlow())
|
val model = createModel(campaignFlow = emptyFlow())
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
model.onFooterExtraHeightReady(100.dp)
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
model.onAlreadyActivated(CampaignType.WhaleSwapCashback(campaignId = "1"))
|
model.onAlreadyActivated(CampaignType.WhaleSwapCashback(campaignId = "1"))
|
||||||
|
|
@ -121,37 +118,20 @@ internal class CampaignsModelTest {
|
||||||
verify(exactly = 1) {
|
verify(exactly = 1) {
|
||||||
analyticsEventHandler.send(PromoCampaignsAnalyticsEvent.AlreadyEnrolledScreenOpened())
|
analyticsEventHandler.send(PromoCampaignsAnalyticsEvent.AlreadyEnrolledScreenOpened())
|
||||||
}
|
}
|
||||||
assertThat(model.footerExtraHeightState.value).isEqualTo(0.dp)
|
|
||||||
model.onDestroy()
|
model.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `GIVEN footer height set WHEN onActivated THEN no analytics and height reset`() = runTest {
|
fun `WHEN onActivated THEN no analytics sent`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
val model = createModel(campaignFlow = emptyFlow())
|
val model = createModel(campaignFlow = emptyFlow())
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
model.onFooterExtraHeightReady(100.dp)
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
model.onActivated(CampaignType.WhaleSwapCashback(campaignId = "1"))
|
model.onActivated(CampaignType.WhaleSwapCashback(campaignId = "1"))
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
verify { analyticsEventHandler wasNot Called }
|
verify { analyticsEventHandler wasNot Called }
|
||||||
assertThat(model.footerExtraHeightState.value).isEqualTo(0.dp)
|
|
||||||
model.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `WHEN onFooterExtraHeightReady THEN height state is updated`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val model = createModel(campaignFlow = emptyFlow())
|
|
||||||
advanceUntilIdle()
|
|
||||||
|
|
||||||
// Act
|
|
||||||
model.onFooterExtraHeightReady(42.dp)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assertThat(model.footerExtraHeightState.value).isEqualTo(42.dp)
|
|
||||||
model.onDestroy()
|
model.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue