Updated on 2026-08-14
This commit is contained in:
parent
321b026fb4
commit
5ae666646f
19 changed files with 559 additions and 6 deletions
|
|
@ -54,6 +54,15 @@ object TradeCryptoMiddleware {
|
|||
}
|
||||
|
||||
private fun proceedBuyAction(state: () -> AppState?, action: TradeCryptoAction.Buy) {
|
||||
val isOnrampEnabled = store.inject(DaggerGraphState::onrampFeatureToggles).isFeatureEnabled
|
||||
if (isOnrampEnabled) proceedWithOnramp() else proceedWithLegacyBuyAction(state, action)
|
||||
}
|
||||
|
||||
private fun proceedWithOnramp() {
|
||||
store.dispatchNavigationAction { push(AppRoute.Onramp) }
|
||||
}
|
||||
|
||||
private fun proceedWithLegacyBuyAction(state: () -> AppState?, action: TradeCryptoAction.Buy) {
|
||||
val networkAddress = action.cryptoCurrencyStatus.value.networkAddress
|
||||
?.defaultAddress
|
||||
?.let(NetworkAddress.Address::value)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.features.disclaimer.api.components.DisclaimerComponent
|
|||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.onramp.component.OnrampComponent
|
||||
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.staking.api.navigation.StakingRouter
|
||||
|
|
@ -46,6 +47,7 @@ internal class ChildFactory @Inject constructor(
|
|||
private val disclaimerComponentFactory: DisclaimerComponent.Factory,
|
||||
private val manageTokensComponentFactory: ManageTokensComponent.Factory,
|
||||
private val marketsTokenDetailsComponentFactory: MarketsTokenDetailsComponent.Factory,
|
||||
private val onrampComponentFactory: OnrampComponent.Factory,
|
||||
private val sendRouter: SendRouter,
|
||||
private val tokenDetailsRouter: TokenDetailsRouter,
|
||||
private val walletRouter: WalletRouter,
|
||||
|
|
@ -186,6 +188,13 @@ internal class ChildFactory @Inject constructor(
|
|||
componentFactory = marketsTokenDetailsComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.Onramp -> {
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = OnrampComponent.Params(),
|
||||
componentFactory = onrampComponentFactory,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -288,4 +288,7 @@ sealed class AppRoute(val path: String) : Route {
|
|||
val source: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object Onramp : AppRoute(path = "/onramp")
|
||||
}
|
||||
|
|
@ -14,6 +14,4 @@ internal data class CurrencyNetworkUM(
|
|||
) : SelectableItemUM {
|
||||
|
||||
override val id: String = network.id.value
|
||||
|
||||
data class LongTapConfig(val contractAddress: String, val onLongTap: () -> Unit)
|
||||
}
|
||||
|
|
@ -285,6 +285,18 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider :
|
|||
onDerivationPathSelected = {},
|
||||
),
|
||||
),
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.NetworkSelector(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "0"),
|
||||
name = "Ethereum",
|
||||
derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/0"),
|
||||
canHandleTokens = true,
|
||||
),
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -5,5 +5,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
|||
|
||||
interface OnrampComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Unit, OnrampComponent>
|
||||
class Params
|
||||
|
||||
interface Factory : ComponentFactory<Params, OnrampComponent>
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
|
|
@ -23,11 +24,11 @@ dependencies {
|
|||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
/* AndroidX */
|
||||
/** AndroidX */
|
||||
implementation(deps.androidx.activity.compose)
|
||||
implementation(deps.lifecycle.compose)
|
||||
|
||||
/* Compose */
|
||||
/** Compose */
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.accompanist.systemUiController)
|
||||
|
|
@ -35,4 +36,8 @@ dependencies {
|
|||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.shimmer)
|
||||
implementation(deps.compose.coil)
|
||||
implementation(deps.compose.material)
|
||||
|
||||
/** Other */
|
||||
implementation(deps.decompose.ext.compose)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.onramp.component
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
|
||||
internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val countryName: String,
|
||||
val isOnrampSupported: Boolean,
|
||||
val countryFlagUrl: String,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, ConfirmResidencyComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tangem.features.onramp.component.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
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.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.features.onramp.component.ConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.model.ConfirmResidencyModel
|
||||
import com.tangem.features.onramp.ui.ConfirmResidencyBottomSheet
|
||||
import com.tangem.features.onramp.ui.ConfirmResidencyBottomSheetContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultConfirmResidencyComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: ConfirmResidencyComponent.Params,
|
||||
) : ConfirmResidencyComponent, AppComponentContext by context {
|
||||
|
||||
private val model: ConfirmResidencyModel = getOrCreateModel(params)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val bottomSheetConfig = remember {
|
||||
TangemBottomSheetConfig(
|
||||
isShow = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
}
|
||||
ConfirmResidencyBottomSheet(
|
||||
config = bottomSheetConfig,
|
||||
content = { modifier ->
|
||||
ConfirmResidencyBottomSheetContent(model = state, modifier = modifier)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ConfirmResidencyComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: ConfirmResidencyComponent.Params,
|
||||
): DefaultConfirmResidencyComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.tangem.features.onramp.component.impl
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.features.onramp.component.OnrampComponent
|
||||
import com.tangem.features.onramp.component.ConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.entity.OnrampBottomSheetConfig
|
||||
import com.tangem.features.onramp.model.OnrampModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultOnrampComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: OnrampComponent.Params,
|
||||
private val confirmResidencyComponentFactory: ConfirmResidencyComponent.Factory,
|
||||
) : OnrampComponent, AppComponentContext by context {
|
||||
|
||||
private val model: OnrampModel = getOrCreateModel(params)
|
||||
private val confirmResidencyBottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = null,
|
||||
handleBackButton = false,
|
||||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val bottomSheet by confirmResidencyBottomSheetSlot.subscribeAsState()
|
||||
BackHandler(onBack = router::pop)
|
||||
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(
|
||||
config: OnrampBottomSheetConfig,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent = when (config) {
|
||||
OnrampBottomSheetConfig.ConfirmResidency -> confirmResidencyComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = ConfirmResidencyComponent.Params(
|
||||
countryName = "United States",
|
||||
isOnrampSupported = true,
|
||||
countryFlagUrl = "https://hatscripts.github.io/circle-flags/flags/us.svg",
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : OnrampComponent.Factory {
|
||||
override fun create(context: AppComponentContext, params: OnrampComponent.Params): DefaultOnrampComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tangem.features.onramp.component.preview
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.features.onramp.component.ConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.entity.ConfirmResidencyUM
|
||||
import com.tangem.features.onramp.ui.ConfirmResidencyBottomSheet
|
||||
import com.tangem.features.onramp.ui.ConfirmResidencyBottomSheetContent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
internal class PreviewConfirmResidencyComponent(
|
||||
initialState: ConfirmResidencyUM = ConfirmResidencyUM(
|
||||
country = "United States",
|
||||
countryFlagUrl = "https://hatscripts.github.io/circle-flags/flags/us.svg",
|
||||
isCountrySupported = true,
|
||||
primaryButtonConfig = ConfirmResidencyUM.ActionButtonConfig(onClick = {}, text = stringReference("Confirm")),
|
||||
secondaryButtonConfig = ConfirmResidencyUM.ActionButtonConfig(onClick = {}, text = stringReference("Change")),
|
||||
),
|
||||
) : ConfirmResidencyComponent {
|
||||
|
||||
private val previewState: MutableStateFlow<ConfirmResidencyUM> = MutableStateFlow(initialState)
|
||||
|
||||
override fun dismiss() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by previewState.collectAsStateWithLifecycle()
|
||||
val bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShow = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
ConfirmResidencyBottomSheet(
|
||||
config = bottomSheetConfig,
|
||||
content = { modifier ->
|
||||
ConfirmResidencyBottomSheetContent(model = state, modifier = modifier)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.onramp.di
|
||||
|
||||
import com.tangem.features.onramp.component.ConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.component.OnrampComponent
|
||||
import com.tangem.features.onramp.component.impl.DefaultConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.component.impl.DefaultOnrampComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface OnrampComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindOnrampComponentFactory(factory: DefaultOnrampComponent.Factory): OnrampComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindConfirmResidencyComponentFactory(
|
||||
factory: DefaultConfirmResidencyComponent.Factory,
|
||||
): ConfirmResidencyComponent.Factory
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object FeatureModule {
|
||||
internal object OnrampFeatureModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.onramp.di
|
||||
|
||||
import com.tangem.core.decompose.di.DecomposeComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.onramp.model.OnrampModel
|
||||
import com.tangem.features.onramp.model.ConfirmResidencyModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(DecomposeComponent::class)
|
||||
internal interface OnrampModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(OnrampModel::class)
|
||||
fun provideOnrampModel(model: OnrampModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(ConfirmResidencyModel::class)
|
||||
fun provideConfirmResidencyModel(model: ConfirmResidencyModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.onramp.entity
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
data class ConfirmResidencyUM(
|
||||
val country: String,
|
||||
val countryFlagUrl: String,
|
||||
val isCountrySupported: Boolean,
|
||||
val primaryButtonConfig: ActionButtonConfig,
|
||||
val secondaryButtonConfig: ActionButtonConfig,
|
||||
) {
|
||||
data class ActionButtonConfig(
|
||||
val onClick: () -> Unit,
|
||||
val text: TextReference,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.onramp.entity
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal sealed class OnrampBottomSheetConfig {
|
||||
|
||||
@Serializable
|
||||
data object ConfirmResidency : OnrampBottomSheetConfig()
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.tangem.features.onramp.model
|
||||
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.onramp.component.ConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.entity.ConfirmResidencyUM
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@ComponentScoped
|
||||
internal class ConfirmResidencyModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
private val params: ConfirmResidencyComponent.Params = paramsContainer.require()
|
||||
val state: MutableStateFlow<ConfirmResidencyUM> = MutableStateFlow(
|
||||
ConfirmResidencyUM(
|
||||
country = params.countryName,
|
||||
countryFlagUrl = params.countryFlagUrl,
|
||||
isCountrySupported = params.isOnrampSupported,
|
||||
primaryButtonConfig = getPrimaryButtonConfig(),
|
||||
secondaryButtonConfig = ConfirmResidencyUM.ActionButtonConfig(
|
||||
onClick = ::onChangeClick,
|
||||
text = resourceReference(R.string.common_change),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
private fun getPrimaryButtonConfig() = if (params.isOnrampSupported) {
|
||||
ConfirmResidencyUM.ActionButtonConfig(
|
||||
onClick = params.onDismiss,
|
||||
text = resourceReference(R.string.common_confirm),
|
||||
)
|
||||
} else {
|
||||
ConfirmResidencyUM.ActionButtonConfig(
|
||||
onClick = ::onCloseClick,
|
||||
text = resourceReference(R.string.common_close),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("EmptyFunctionBlock")
|
||||
private fun onCloseClick() {
|
||||
}
|
||||
|
||||
private fun onChangeClick() {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.features.onramp.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.features.onramp.component.OnrampComponent
|
||||
import com.tangem.features.onramp.entity.OnrampBottomSheetConfig
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@ComponentScoped
|
||||
internal class OnrampModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private val params: OnrampComponent.Params = paramsContainer.require()
|
||||
val bottomSheetNavigation: SlotNavigation<OnrampBottomSheetConfig> = SlotNavigation()
|
||||
|
||||
init {
|
||||
modelScope.launch {
|
||||
delay(1500)
|
||||
bottomSheetNavigation.activate(OnrampBottomSheetConfig.ConfirmResidency)
|
||||
}
|
||||
}
|
||||
|
||||
fun pop() {
|
||||
router.pop()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
package com.tangem.features.onramp.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBarHeight
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.onramp.component.ConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.component.preview.PreviewConfirmResidencyComponent
|
||||
import com.tangem.features.onramp.entity.ConfirmResidencyUM
|
||||
import com.tangem.features.onramp.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun ConfirmResidencyBottomSheet(config: TangemBottomSheetConfig, content: @Composable (Modifier) -> Unit) {
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = config,
|
||||
addBottomInsets = true,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
title = { _ -> Title() },
|
||||
content = {
|
||||
val contentModifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.padding(bottom = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
|
||||
content(contentModifier)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Title(modifier: Modifier = Modifier) {
|
||||
TangemTopAppBar(
|
||||
modifier = modifier,
|
||||
title = resourceReference(R.string.onramp_residency_bottomsheet_title),
|
||||
titleAlignment = Alignment.CenterHorizontally,
|
||||
height = TangemTopAppBarHeight.BOTTOM_SHEET,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ConfirmResidencyBottomSheetContent(model: ConfirmResidencyUM, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier) {
|
||||
CountryContent(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens.spacing24),
|
||||
name = model.country,
|
||||
flagUrl = model.countryFlagUrl,
|
||||
isCountrySupported = model.isCountrySupported,
|
||||
)
|
||||
SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = model.secondaryButtonConfig.text.resolveReference(),
|
||||
onClick = model.secondaryButtonConfig.onClick,
|
||||
)
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = TangemTheme.dimens.spacing12),
|
||||
text = model.primaryButtonConfig.text.resolveReference(),
|
||||
onClick = model.primaryButtonConfig.onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CountryContent(name: String, flagUrl: String, isCountrySupported: Boolean, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
val flagSize = with(LocalDensity.current) { TangemTheme.dimens.size36.roundToPx() }
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size36),
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.size(size = flagSize)
|
||||
.data(flagUrl)
|
||||
.memoryCacheKey(flagUrl + flagSize)
|
||||
.crossfade(true)
|
||||
.allowHardware(false)
|
||||
.build(),
|
||||
loading = { CircleShimmer() },
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing12),
|
||||
text = name,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing6),
|
||||
text = stringResource(
|
||||
id = if (isCountrySupported) {
|
||||
R.string.onramp_residency_bottomsheet_country_subtitle
|
||||
} else {
|
||||
R.string.onramp_residency_bottomsheet_country_not_supported
|
||||
},
|
||||
),
|
||||
color = if (isCountrySupported) TangemTheme.colors.text.tertiary else TangemTheme.colors.text.warning,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_ConfirmResidencyBottomSheet(
|
||||
@PreviewParameter(ConfirmResidencyComponentPreviewProvider::class) component: ConfirmResidencyComponent,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
component.BottomSheet()
|
||||
}
|
||||
}
|
||||
|
||||
private class ConfirmResidencyComponentPreviewProvider : PreviewParameterProvider<ConfirmResidencyComponent> {
|
||||
override val values: Sequence<ConfirmResidencyComponent>
|
||||
get() = sequenceOf(
|
||||
PreviewConfirmResidencyComponent(),
|
||||
PreviewConfirmResidencyComponent(
|
||||
initialState = ConfirmResidencyUM(
|
||||
country = "Russia",
|
||||
countryFlagUrl = "https://hatscripts.github.io/circle-flags/flags/ru.svg",
|
||||
isCountrySupported = false,
|
||||
primaryButtonConfig = ConfirmResidencyUM.ActionButtonConfig(
|
||||
onClick = {},
|
||||
text = stringReference("Close"),
|
||||
),
|
||||
secondaryButtonConfig = ConfirmResidencyUM.ActionButtonConfig(
|
||||
onClick = {},
|
||||
text = stringReference("Change"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue