diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 615b1c3778..9a80508e7b 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -17,6 +17,7 @@ import com.tangem.features.disclaimer.api.components.DisclaimerComponent import com.tangem.features.home.api.HomeComponent import com.tangem.features.hotwallet.AddExistingWalletComponent import com.tangem.features.hotwallet.CreateMobileWalletComponent +import com.tangem.features.hotwallet.UpgradeWalletComponent import com.tangem.features.hotwallet.WalletActivationComponent import com.tangem.features.hotwallet.CreateWalletBackupComponent import com.tangem.features.hotwallet.UpdateAccessCodeComponent @@ -103,6 +104,7 @@ internal class ChildFactory @Inject constructor( private val chooseManagedTokensComponentFactory: ChooseManagedTokensComponent.Factory, private val createWalletSelectionComponentFactory: CreateWalletSelectionComponent.Factory, private val createMobileWalletComponentFactory: CreateMobileWalletComponent.Factory, + private val upgradeWalletComponentFactory: UpgradeWalletComponent.Factory, private val addExistingWalletComponentFactory: AddExistingWalletComponent.Factory, private val walletActivationComponentFactory: WalletActivationComponent.Factory, private val createWalletBackupComponentFactory: CreateWalletBackupComponent.Factory, @@ -486,6 +488,15 @@ internal class ChildFactory @Inject constructor( componentFactory = createMobileWalletComponentFactory, ) } + is AppRoute.UpgradeWallet -> { + createComponentChild( + context = context, + params = UpgradeWalletComponent.Params( + userWalletId = route.userWalletId, + ), + componentFactory = upgradeWalletComponentFactory, + ) + } is AppRoute.AddExistingWallet -> { createComponentChild( context = context, diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index d0ffcca403..cfa1070c25 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -311,6 +311,11 @@ sealed class AppRoute(val path: String) : Route { @Serializable object CreateMobileWallet : AppRoute(path = "/create_mobile_wallet") + @Serializable + data class UpgradeWallet( + val userWalletId: UserWalletId, + ) : AppRoute(path = "/upgrade_wallet/${userWalletId.stringValue}") + @Serializable object AddExistingWallet : AppRoute(path = "/add_existing_wallet") diff --git a/core/ui/src/main/res/drawable/ic_knight_shield_24.xml b/core/ui/src/main/res/drawable/ic_knight_shield_24.xml new file mode 100644 index 0000000000..1a058ff367 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_knight_shield_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/ui/src/main/res/drawable/ic_mobile_security_24.xml b/core/ui/src/main/res/drawable/ic_mobile_security_24.xml new file mode 100644 index 0000000000..bbc69392d5 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_mobile_security_24.xml @@ -0,0 +1,12 @@ + + + + diff --git a/core/ui/src/main/res/drawable/ic_protect_24.xml b/core/ui/src/main/res/drawable/ic_protect_24.xml new file mode 100644 index 0000000000..5ad478076f --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_protect_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/ui/src/main/res/drawable/ic_tangem_64.xml b/core/ui/src/main/res/drawable/ic_tangem_64.xml new file mode 100644 index 0000000000..6c39da496c --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_tangem_64.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/UpgradeWalletComponent.kt b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/UpgradeWalletComponent.kt new file mode 100644 index 0000000000..8a9b7f6c14 --- /dev/null +++ b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/UpgradeWalletComponent.kt @@ -0,0 +1,14 @@ +package com.tangem.features.hotwallet + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.models.wallet.UserWalletId + +interface UpgradeWalletComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/DefaultUpgradeWalletComponent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/DefaultUpgradeWalletComponent.kt new file mode 100644 index 0000000000..2f0e91d1de --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/DefaultUpgradeWalletComponent.kt @@ -0,0 +1,39 @@ +package com.tangem.features.hotwallet.upgradewallet + +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 com.tangem.features.hotwallet.UpgradeWalletComponent +import com.tangem.features.hotwallet.upgradewallet.ui.UpgradeWalletContent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +@Suppress("UnusedPrivateMember") +internal class DefaultUpgradeWalletComponent @AssistedInject constructor( + @Assisted private val context: AppComponentContext, + @Assisted private val params: UpgradeWalletComponent.Params, +) : UpgradeWalletComponent, AppComponentContext by context { + + private val model: UpgradeWalletModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val state by model.uiState.collectAsStateWithLifecycle() + UpgradeWalletContent( + state = state, + modifier = modifier, + ) + } + + @AssistedFactory + interface Factory : UpgradeWalletComponent.Factory { + override fun create( + context: AppComponentContext, + params: UpgradeWalletComponent.Params, + ): DefaultUpgradeWalletComponent + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt new file mode 100644 index 0000000000..bc03e54e43 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt @@ -0,0 +1,41 @@ +package com.tangem.features.hotwallet.upgradewallet + +import com.tangem.core.decompose.di.ModelScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.navigation.Router +import com.tangem.core.navigation.url.UrlOpener +import com.tangem.domain.wallets.usecase.GenerateBuyTangemCardLinkUseCase +import com.tangem.features.hotwallet.upgradewallet.entity.UpgradeWalletUM +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@ModelScoped +internal class UpgradeWalletModel @Inject constructor( + override val dispatchers: CoroutineDispatcherProvider, + private val router: Router, + private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, + private val urlOpener: UrlOpener, +) : Model() { + + internal val uiState: StateFlow + field = MutableStateFlow( + UpgradeWalletUM( + onBackClick = { router.pop() }, + onBuyTangemWalletClick = ::onBuyTangemWalletClick, + onScanDeviceClick = ::onScanDeviceClick, + ), + ) + + private fun onBuyTangemWalletClick() { + modelScope.launch { + generateBuyTangemCardLinkUseCase.invoke().let { urlOpener.openUrl(it) } + } + } + + private fun onScanDeviceClick() { + // TODO [REDACTED_TASK_KEY] + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/di/UpgradeWalletModule.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/di/UpgradeWalletModule.kt new file mode 100644 index 0000000000..3beb13bcab --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/di/UpgradeWalletModule.kt @@ -0,0 +1,25 @@ +package com.tangem.features.hotwallet.upgradewallet.di + +import com.tangem.core.decompose.model.Model +import com.tangem.features.hotwallet.UpgradeWalletComponent +import com.tangem.features.hotwallet.upgradewallet.DefaultUpgradeWalletComponent +import com.tangem.features.hotwallet.upgradewallet.UpgradeWalletModel +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +@InstallIn(SingletonComponent::class) +internal interface UpgradeWalletModule { + + @Binds + fun bindUpgradeWalletComponentFactory(impl: DefaultUpgradeWalletComponent.Factory): UpgradeWalletComponent.Factory + + @Binds + @IntoMap + @ClassKey(UpgradeWalletModel::class) + fun bindUpgradeWalletModel(model: UpgradeWalletModel): Model +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/entity/UpgradeWalletUM.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/entity/UpgradeWalletUM.kt new file mode 100644 index 0000000000..8f700a27b9 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/entity/UpgradeWalletUM.kt @@ -0,0 +1,7 @@ +package com.tangem.features.hotwallet.upgradewallet.entity + +internal data class UpgradeWalletUM( + val onBackClick: () -> Unit, + val onBuyTangemWalletClick: () -> Unit, + val onScanDeviceClick: () -> Unit, +) \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt new file mode 100644 index 0000000000..2ae6ae5d0c --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/ui/UpgradeWalletContent.kt @@ -0,0 +1,161 @@ +package com.tangem.features.hotwallet.upgradewallet.ui + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +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.R +import com.tangem.core.ui.components.PrimaryButtonIconEnd +import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.components.appbar.TangemTopAppBar +import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.stringResourceSafe +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.hotwallet.upgradewallet.entity.UpgradeWalletUM + +@Suppress("LongMethod") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun UpgradeWalletContent(state: UpgradeWalletUM, modifier: Modifier = Modifier) { + Column( + modifier = modifier + .background(TangemTheme.colors.background.primary) + .fillMaxSize() + .systemBarsPadding(), + ) { + TangemTopAppBar( + modifier = Modifier + .statusBarsPadding(), + startButton = TopAppBarButtonUM.Back(state.onBackClick), + title = TextReference.EMPTY, + ) + Column( + modifier = Modifier + .weight(1f) + .padding( + start = 16.dp, + top = 24.dp, + end = 16.dp, + ), + ) { + Icon( + modifier = Modifier + .fillMaxWidth(), + painter = painterResource(R.drawable.ic_tangem_64), + contentDescription = null, + tint = Color.Unspecified, + ) + Text( + modifier = Modifier + .fillMaxWidth() + .padding( + start = 16.dp, + top = 20.dp, + end = 16.dp, + ), + text = stringResourceSafe(R.string.hw_upgrade_title), + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.Center, + ) + FeatureBlock( + modifier = Modifier + .padding(top = 32.dp), + title = stringResourceSafe(R.string.hw_upgrade_key_migration_title), + description = stringResourceSafe(R.string.hw_upgrade_key_migration_description), + iconRes = R.drawable.ic_mobile_security_24, + ) + FeatureBlock( + modifier = Modifier + .padding(top = 24.dp), + title = stringResourceSafe(R.string.hw_upgrade_funds_access_title), + description = stringResourceSafe(R.string.hw_upgrade_funds_access_description), + iconRes = R.drawable.ic_knight_shield_24, + ) + FeatureBlock( + modifier = Modifier + .padding(top = 24.dp), + title = stringResourceSafe(R.string.hw_upgrade_general_security_title), + description = stringResourceSafe(R.string.hw_upgrade_general_security_description), + iconRes = R.drawable.ic_protect_24, + ) + } + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + SecondaryButton( + modifier = Modifier + .fillMaxWidth(), + text = stringResourceSafe(R.string.details_buy_wallet), + onClick = state.onBuyTangemWalletClick, + ) + PrimaryButtonIconEnd( + modifier = Modifier + .fillMaxWidth(), + text = stringResourceSafe(R.string.hw_upgrade_scan_device), + onClick = state.onScanDeviceClick, + iconResId = R.drawable.ic_tangem_24, + ) + } + } +} + +@Composable +private fun FeatureBlock(title: String, description: String, iconRes: Int, modifier: Modifier = Modifier) { + Row( + modifier = modifier, + ) { + Icon( + modifier = Modifier + .padding(horizontal = 12.dp), + painter = painterResource(iconRes), + contentDescription = null, + tint = TangemTheme.colors.icon.primary1, + ) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + ) { + Text( + text = title, + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + ) + Text( + modifier = Modifier + .padding(top = 4.dp), + text = description, + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.secondary, + ) + } + } +} + +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewUpgradeWalletContent() { + TangemThemePreview { + UpgradeWalletContent( + state = UpgradeWalletUM( + onBackClick = {}, + onBuyTangemWalletClick = {}, + onScanDeviceClick = {}, + ), + ) + } +} \ No newline at end of file