From 37efabe359ba0f2ad6987e3f15fa96bd0b5c54d5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 24 Jun 2025 15:44:11 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../create-wallet-selection/api/.gitignore | 1 + .../api/build.gradle.kts | 22 ++ .../CreateWalletSelectionComponent.kt | 8 + .../create-wallet-selection/impl/.gitignore | 1 + .../impl/build.gradle.kts | 70 +++++ .../CreateWalletSelectionContent.kt | 240 ++++++++++++++++++ .../CreateWalletSelectionFeatureModule.kt | 30 +++ .../CreateWalletSelectionModel.kt | 37 +++ .../DefaultCreateWalletSelectionComponent.kt | 33 +++ .../entity/CreateWalletSelectionUM.kt | 9 + settings.gradle.kts | 3 + 11 files changed, 454 insertions(+) create mode 100644 features/create-wallet-selection/api/.gitignore create mode 100644 features/create-wallet-selection/api/build.gradle.kts create mode 100644 features/create-wallet-selection/api/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionComponent.kt create mode 100644 features/create-wallet-selection/impl/.gitignore create mode 100644 features/create-wallet-selection/impl/build.gradle.kts create mode 100644 features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionContent.kt create mode 100644 features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionFeatureModule.kt create mode 100644 features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt create mode 100644 features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/DefaultCreateWalletSelectionComponent.kt create mode 100644 features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt diff --git a/features/create-wallet-selection/api/.gitignore b/features/create-wallet-selection/api/.gitignore new file mode 100644 index 0000000000..d3b3de5967 --- /dev/null +++ b/features/create-wallet-selection/api/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/features/create-wallet-selection/api/build.gradle.kts b/features/create-wallet-selection/api/build.gradle.kts new file mode 100644 index 0000000000..2ffb19aeee --- /dev/null +++ b/features/create-wallet-selection/api/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.createwalletselection.api" +} + +dependencies { + + /* Project - Domain */ + implementation(projects.domain.models) + + /* Project - Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /* Compose */ + implementation(deps.compose.runtime) +} \ No newline at end of file diff --git a/features/create-wallet-selection/api/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionComponent.kt b/features/create-wallet-selection/api/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionComponent.kt new file mode 100644 index 0000000000..cadc5950f1 --- /dev/null +++ b/features/create-wallet-selection/api/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionComponent.kt @@ -0,0 +1,8 @@ +package com.tangem.features.createwalletselection + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent + +interface CreateWalletSelectionComponent : ComposableContentComponent { + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/create-wallet-selection/impl/.gitignore b/features/create-wallet-selection/impl/.gitignore new file mode 100644 index 0000000000..d3b3de5967 --- /dev/null +++ b/features/create-wallet-selection/impl/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/features/create-wallet-selection/impl/build.gradle.kts b/features/create-wallet-selection/impl/build.gradle.kts new file mode 100644 index 0000000000..828a0ccfac --- /dev/null +++ b/features/create-wallet-selection/impl/build.gradle.kts @@ -0,0 +1,70 @@ +plugins { + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.kotlin.serialization) + alias(deps.plugins.hilt.android) + id("configuration") +} + +android { + namespace = "com.tangem.features.createwalletselection.impl" +} + +dependencies { + /** Api */ + implementation(projects.features.createWalletSelection.api) + + /** Hot Wallet Feature */ + implementation(projects.features.hotWallet.api) + + /** Core modules */ + implementation(projects.core.configToggles) + implementation(projects.core.analytics) + implementation(projects.core.analytics.models) + implementation(projects.core.utils) + implementation(projects.core.ui) + implementation(projects.core.res) + implementation(projects.core.decompose) + implementation(projects.core.navigation) + implementation(projects.core.datasource) + + /** Common */ + implementation(projects.common.ui) + implementation(projects.common.routing) + + /** Tangem libraries */ + implementation(projects.libs.tangemSdkApi) + implementation(tangemDeps.card.core) + implementation(tangemDeps.card.android) { + exclude(module = "joda-time") + } + + /** AndroidX libraries */ + implementation(deps.androidx.core.ktx) + implementation(deps.lifecycle.runtime.ktx) + + /** Compose libraries */ + implementation(deps.compose.material) + implementation(deps.compose.material3) + implementation(deps.compose.animation) + implementation(deps.compose.foundation) + implementation(deps.compose.ui) + implementation(deps.compose.ui.tooling) + implementation(deps.compose.coil) + implementation(deps.lottie.compose) + implementation(deps.decompose.ext.compose) + implementation(deps.androidx.activity.compose) + implementation(deps.androidx.datastore) + + /** Other libraries */ + implementation(deps.arrow.core) + implementation(deps.kotlin.immutable.collections) + implementation(deps.kotlin.serialization) + implementation(deps.timber) + implementation(deps.firebase.crashlytics) + + /** DI */ + implementation(deps.hilt.android) + kapt(deps.hilt.kapt) +} \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionContent.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionContent.kt new file mode 100644 index 0000000000..ad39c3191b --- /dev/null +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionContent.kt @@ -0,0 +1,240 @@ +package com.tangem.features.createwalletselection + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +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.buttons.common.TangemButton +import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition +import com.tangem.core.ui.components.buttons.common.TangemButtonSize +import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.createwalletselection.entity.CreateWalletSelectionUM +import com.tangem.features.createwalletselection.impl.R + +@Suppress("LongMethod") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun CreateWalletSelectionContent(state: CreateWalletSelectionUM, modifier: Modifier = Modifier) { + Column( + modifier = Modifier + .background(TangemTheme.colors.background.primary) + .fillMaxSize() + .systemBarsPadding(), + ) { + TopAppBar( + modifier = modifier + .statusBarsPadding(), + colors = TopAppBarDefaults.topAppBarColors( + containerColor = TangemTheme.colors.background.primary, + ), + navigationIcon = { + IconButton(onClick = state.onBackClick) { + Icon( + painter = painterResource(R.drawable.ic_back_24), + tint = TangemTheme.colors.icon.primary1, + contentDescription = null, + ) + } + }, + title = { }, + actions = { + Text( + modifier = Modifier + .padding(16.dp), + // TODO update and extract this string + text = "What to choose?", + style = TangemTheme.typography.body1, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + ) + Column( + modifier = Modifier + .weight(1f) + .padding( + start = 16.dp, + top = 24.dp, + end = 16.dp, + ), + ) { + Text( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + // TODO update and extract this string + text = "Choose how you want to create your wallet", + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + ) + WalletBlock( + modifier = Modifier + .padding(top = 24.dp), + // TODO update and extract this string + title = "Mobile Wallet", + // TODO update and extract this string + description = "A secure wallet is created on your phone in seconds.", + badge = { + Box( + modifier = Modifier + .background( + color = TangemTheme.colors.field.focused, + shape = TangemTheme.shapes.roundedCorners8, + ) + .padding(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + // TODO update and extract this string + text = "Free", + style = TangemTheme.typography.caption1, + color = TangemTheme.colors.text.secondary, + ) + } + }, + onClick = state.onMobileWalletClick, + ) + WalletBlock( + // TODO update and extract this string + title = "Hardware Wallet", + // TODO update and extract this string + description = "Buy Tangem Wallet — physical cards that securely store your crypto offline.", + badge = { + Box( + modifier = Modifier + .background( + color = TangemTheme.colors.text.accent.copy(alpha = 0.1f), + shape = TangemTheme.shapes.roundedCorners8, + ) + .padding(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + // TODO update and extract this string + text = "From $54.90", + style = TangemTheme.typography.caption1, + color = TangemTheme.colors.text.accent, + ) + } + }, + onClick = state.onHardwareWalletClick, + ) + } + AlreadyHaveTangemWalletBlock( + onScanClick = state.onScanClick, + isScanInProgress = state.isScanInProgress, + ) + } +} + +@Composable +private fun WalletBlock( + modifier: Modifier = Modifier, + title: String, + description: String, + badge: @Composable () -> Unit, + onClick: () -> Unit, +) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(top = 8.dp) + .background( + color = TangemTheme.colors.background.secondary, + shape = TangemTheme.shapes.roundedCornersXMedium, + ) + .padding(16.dp) + .clickable(onClick = onClick), + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + modifier = Modifier + .padding(end = 8.dp), + text = title, + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + ) + badge() + } + Text( + modifier = Modifier + .padding(top = 4.dp), + text = description, + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.tertiary, + ) + } +} + +@Composable +private fun AlreadyHaveTangemWalletBlock( + onScanClick: () -> Unit, + isScanInProgress: Boolean, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(16.dp) + .background( + color = TangemTheme.colors.field.primary, + shape = TangemTheme.shapes.roundedCornersXMedium, + ) + .padding( + horizontal = 20.dp, + vertical = 16.dp, + ), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + modifier = Modifier + .weight(1f) + .padding(end = 16.dp), + // TODO update and extract this string + text = "Do you already have Tangem Wallet?", + style = TangemTheme.typography.button, + color = TangemTheme.colors.text.primary1, + ) + TangemButton( + modifier = Modifier + .wrapContentWidth(), + // TODO update and extract this string + text = "Scan Now", + onClick = onScanClick, + icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24), + size = TangemButtonSize.RoundedAction, + showProgress = isScanInProgress, + colors = TangemButtonsDefaults.secondaryButtonColors, + textStyle = TangemTheme.typography.subtitle1, + enabled = true, + animateContentChange = true, + ) + } +} + +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewCreateWalletContent() { + TangemThemePreview { + CreateWalletSelectionContent( + state = CreateWalletSelectionUM( + onBackClick = {}, + onMobileWalletClick = {}, + onHardwareWalletClick = {}, + onScanClick = {}, + ), + ) + } +} \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionFeatureModule.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionFeatureModule.kt new file mode 100644 index 0000000000..a810f1ba9f --- /dev/null +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionFeatureModule.kt @@ -0,0 +1,30 @@ +package com.tangem.features.createwalletselection + +import com.tangem.core.decompose.model.Model +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object CreateWalletSelectionFeatureModule + +@Module +@InstallIn(SingletonComponent::class) +internal interface CreateWalletSelectionFeatureModuleBinds { + + @Binds + @Singleton + fun bindCreateWalletSelectionComponentFactory( + impl: DefaultCreateWalletSelectionComponent.Factory, + ): CreateWalletSelectionComponent.Factory + + @Binds + @IntoMap + @ClassKey(CreateWalletSelectionModel::class) + fun bindCreateWalletSelectionModel(model: CreateWalletSelectionModel): Model +} \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt new file mode 100644 index 0000000000..0299618954 --- /dev/null +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt @@ -0,0 +1,37 @@ +package com.tangem.features.createwalletselection + +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.features.createwalletselection.entity.CreateWalletSelectionUM +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ModelScoped +internal class CreateWalletSelectionModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, +) : Model() { + + internal val uiState: StateFlow + field = MutableStateFlow( + CreateWalletSelectionUM( + onBackClick = { /* [REDACTED_TODO_COMMENT] */ }, + onMobileWalletClick = ::onMobileWalletClick, + onHardwareWalletClick = ::onHardwareWalletClick, + onScanClick = ::onScanClick, + ), + ) + + private fun onMobileWalletClick() { + // TODO navigate to mobile wallet creation + } + + private fun onHardwareWalletClick() { + // TODO open card order web page + } + + private fun onScanClick() { + // TODO open card scanning + } +} \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/DefaultCreateWalletSelectionComponent.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/DefaultCreateWalletSelectionComponent.kt new file mode 100644 index 0000000000..7eede00b99 --- /dev/null +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/DefaultCreateWalletSelectionComponent.kt @@ -0,0 +1,33 @@ +package com.tangem.features.createwalletselection + +import androidx.compose.runtime.Composable +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 dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultCreateWalletSelectionComponent @AssistedInject constructor( + @Assisted private val context: AppComponentContext, + @Assisted private val params: Unit, +) : CreateWalletSelectionComponent, AppComponentContext by context { + + private val model: CreateWalletSelectionModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val state by model.uiState.collectAsStateWithLifecycle() + CreateWalletSelectionContent( + state = state, + modifier = modifier, + ) + } + + @AssistedFactory + interface Factory : CreateWalletSelectionComponent.Factory { + override fun create(context: AppComponentContext, params: Unit): DefaultCreateWalletSelectionComponent + } +} \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt new file mode 100644 index 0000000000..70c95a5b38 --- /dev/null +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt @@ -0,0 +1,9 @@ +package com.tangem.features.createwalletselection.entity + +internal data class CreateWalletSelectionUM( + val isScanInProgress: Boolean = false, + val onBackClick: () -> Unit, + val onMobileWalletClick: () -> Unit, + val onHardwareWalletClick: () -> Unit, + val onScanClick: () -> Unit, +) \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index eca5b3d022..ba875e3bb9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -251,6 +251,9 @@ include(":features:hot-wallet:impl") include(":features:kyc:api") include(":features:kyc:impl") + +include(":features:create-wallet-selection:api") +include(":features:create-wallet-selection:impl") // endregion Feature modules // region Domain modules