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 5bdb2476f6..e28474943c 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 @@ -8,6 +8,7 @@ import com.tangem.feature.referral.api.ReferralComponent import com.tangem.feature.stories.api.StoriesComponent import com.tangem.feature.usedesk.api.UsedeskComponent import com.tangem.feature.walletsettings.component.WalletSettingsComponent +import com.tangem.features.hotwallet.WalletBackupComponent import com.tangem.features.createwalletselection.CreateWalletSelectionComponent import com.tangem.features.details.component.DetailsComponent import com.tangem.features.disclaimer.api.components.DisclaimerComponent @@ -51,6 +52,7 @@ import com.tangem.features.walletconnect.components.WalletConnectEntryComponent internal class ChildFactory @Inject constructor( private val detailsComponentFactory: DetailsComponent.Factory, private val walletSettingsComponentFactory: WalletSettingsComponent.Factory, + private val walletBackupComponentFactory: WalletBackupComponent.Factory, private val disclaimerComponentFactory: DisclaimerComponent.Factory, private val manageTokensComponentFactory: ManageTokensComponent.Factory, private val marketsTokenDetailsComponentFactory: MarketsTokenDetailsComponent.Factory, @@ -141,6 +143,15 @@ internal class ChildFactory @Inject constructor( componentFactory = walletSettingsComponentFactory, ) } + is AppRoute.WalletBackup -> { + createComponentChild( + context = context, + params = WalletBackupComponent.Params( + userWalletId = route.userWalletId, + ), + componentFactory = walletBackupComponentFactory, + ) + } is AppRoute.MarketsTokenDetails -> { 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 d403d0800b..4f2fdceec3 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 @@ -191,6 +191,11 @@ sealed class AppRoute(val path: String) : Route { val userWalletId: UserWalletId, ) : AppRoute(path = "/wallet_settings/${userWalletId.stringValue}") + @Serializable + data class WalletBackup( + val userWalletId: UserWalletId, + ) : AppRoute(path = "/wallet_backup/${userWalletId.stringValue}") + @Serializable data object Markets : AppRoute(path = "/markets") diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 1e513517d1..a2aa6ee2c6 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -425,8 +425,8 @@ To complete setup, back up your wallet and secure app access with a Access Code. Finish Now Finish Wallet Activation - Recover an existing wallet stored in your iCloud backup - iCloud backup + Recover an existing wallet stored in your Google Drive backup + Google Drive Backup Go to backup To secure your wallet with a Access Code, complete the backup first. Finish Backup First diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt index 6e412c985b..0c777f9a97 100644 --- a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt @@ -155,7 +155,7 @@ private fun WalletBlock( Row { Text( modifier = Modifier - .weight(1f) + .weight(1f, fill = false) .padding(end = 8.dp), text = title, style = TangemTheme.typography.subtitle1, diff --git a/features/hot-wallet/api/build.gradle.kts b/features/hot-wallet/api/build.gradle.kts index 9b15221cb2..0b7e98f231 100644 --- a/features/hot-wallet/api/build.gradle.kts +++ b/features/hot-wallet/api/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { /* Project - Domain */ implementation(projects.domain.models) + implementation(projects.domain.wallets.models) /* Project - Core */ implementation(projects.core.decompose) diff --git a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.kt b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.kt new file mode 100644 index 0000000000..a422db8dad --- /dev/null +++ b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/WalletBackupComponent.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.wallets.models.UserWalletId + +interface WalletBackupComponent : 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/addexistingwallet/start/ui/AddExistingWalletStartContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/start/ui/AddExistingWalletStartContent.kt index 66e907f5d8..eef14e30c9 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/start/ui/AddExistingWalletStartContent.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/start/ui/AddExistingWalletStartContent.kt @@ -3,27 +3,27 @@ package com.tangem.features.hotwallet.addexistingwallet.start.ui import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.material3.* +import androidx.compose.material3.ExperimentalMaterial3Api +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.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.PrimaryButton import com.tangem.core.ui.components.appbar.TangemTopAppBar import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM import com.tangem.core.ui.components.buttons.common.TangemButtonSize import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults -import com.tangem.core.ui.extensions.clickableSingle -import com.tangem.core.ui.extensions.conditional +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.addexistingwallet.start.entity.AddExistingWalletStartUM -import com.tangem.core.ui.R -import com.tangem.core.ui.extensions.stringResourceSafe +import com.tangem.features.hotwallet.common.ui.OptionBlock @Suppress("LongMethod") @OptIn(ExperimentalMaterial3Api::class) @@ -62,6 +62,7 @@ internal fun AddExistingWalletStartContent(state: AddExistingWalletStartUM, modi OptionBlock( modifier = Modifier .padding(top = 24.dp), + backgroundColor = TangemTheme.colors.background.secondary, title = stringResourceSafe(R.string.wallet_import_seed_title), description = stringResourceSafe(R.string.wallet_import_seed_description), badge = null, @@ -69,6 +70,7 @@ internal fun AddExistingWalletStartContent(state: AddExistingWalletStartUM, modi enabled = true, ) OptionBlock( + backgroundColor = TangemTheme.colors.background.secondary, title = stringResourceSafe(R.string.wallet_import_scan_title), description = stringResourceSafe(R.string.wallet_import_scan_description), badge = { @@ -85,6 +87,7 @@ internal fun AddExistingWalletStartContent(state: AddExistingWalletStartUM, modi enabled = true, ) OptionBlock( + backgroundColor = TangemTheme.colors.background.secondary, title = stringResourceSafe(R.string.wallet_import_google_drive_title), description = stringResourceSafe(R.string.wallet_import_google_drive_description), badge = { @@ -114,58 +117,6 @@ internal fun AddExistingWalletStartContent(state: AddExistingWalletStartUM, modi } } -@Composable -private fun OptionBlock( - title: String, - description: String, - badge: (@Composable () -> Unit)?, - onClick: (() -> Unit)?, - enabled: Boolean, - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier - .fillMaxWidth() - .padding(top = 8.dp) - .clip(TangemTheme.shapes.roundedCornersXMedium) - .background( - color = TangemTheme.colors.background.secondary, - shape = TangemTheme.shapes.roundedCornersXMedium, - ) - .conditional(onClick != null) { - onClick?.let { clickableSingle(onClick = it) } ?: Modifier - } - .padding(16.dp), - ) { - Row { - Text( - modifier = Modifier - .weight(1f, fill = false) - .padding(end = 4.dp), - text = title, - style = TangemTheme.typography.subtitle1, - color = if (enabled) { - TangemTheme.colors.text.primary1 - } else { - TangemTheme.colors.text.secondary - }, - ) - badge?.invoke() - } - Text( - modifier = Modifier - .padding(top = 4.dp), - text = description, - style = TangemTheme.typography.body2, - color = if (enabled) { - TangemTheme.colors.text.tertiary - } else { - TangemTheme.colors.text.disabled - }, - ) - } -} - @Composable private fun BuyTangemWalletBlock(onScanClick: () -> Unit, modifier: Modifier = Modifier) { Row( diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt new file mode 100644 index 0000000000..ad1d8637e1 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/common/ui/OptionBlock.kt @@ -0,0 +1,88 @@ +package com.tangem.features.hotwallet.common.ui + +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.extensions.clickableSingle +import com.tangem.core.ui.extensions.conditional +import com.tangem.core.ui.res.TangemTheme + +internal const val DISABLED_COLORS_ALPHA = 0.5f + +@Suppress("LongParameterList") +@Composable +internal fun OptionBlock( + title: String, + description: String, + badge: (@Composable () -> Unit)?, + onClick: (() -> Unit)?, + enabled: Boolean, + backgroundColor: Color, + modifier: Modifier = Modifier, +) { + val backgroundColor by animateColorAsState( + targetValue = if (enabled) { + backgroundColor + } else { + backgroundColor.copy(alpha = DISABLED_COLORS_ALPHA) + }, + ) + val titleColor by animateColorAsState( + targetValue = if (enabled) { + TangemTheme.colors.text.primary1 + } else { + TangemTheme.colors.text.primary1.copy(alpha = DISABLED_COLORS_ALPHA) + }, + ) + val descriptionColor by animateColorAsState( + targetValue = if (enabled) { + TangemTheme.colors.text.tertiary + } else { + TangemTheme.colors.text.tertiary.copy(alpha = DISABLED_COLORS_ALPHA) + }, + ) + + Column( + modifier = modifier + .fillMaxWidth() + .padding(top = 8.dp) + .clip(TangemTheme.shapes.roundedCornersXMedium) + .background( + color = backgroundColor, + shape = TangemTheme.shapes.roundedCornersXMedium, + ) + .conditional(onClick != null) { + onClick?.let { clickableSingle(onClick = it) } ?: Modifier + } + .padding(16.dp), + ) { + Row { + Text( + modifier = Modifier + .weight(1f, fill = false) + .padding(end = 4.dp), + text = title, + style = TangemTheme.typography.subtitle1, + color = titleColor, + ) + badge?.invoke() + } + Text( + modifier = Modifier + .padding(top = 4.dp), + text = description, + style = TangemTheme.typography.body2, + color = descriptionColor, + ) + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/component/DefaultWalletBackupComponent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/component/DefaultWalletBackupComponent.kt new file mode 100644 index 0000000000..5c9921bdf6 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/component/DefaultWalletBackupComponent.kt @@ -0,0 +1,39 @@ +package com.tangem.features.hotwallet.walletbackup.component + +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.WalletBackupComponent +import com.tangem.features.hotwallet.walletbackup.model.WalletBackupModel +import com.tangem.features.hotwallet.walletbackup.ui.WalletBackupContent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultWalletBackupComponent @AssistedInject constructor( + @Assisted private val context: AppComponentContext, + @Assisted private val params: WalletBackupComponent.Params, +) : WalletBackupComponent, AppComponentContext by context { + + private val model: WalletBackupModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val state by model.uiState.collectAsStateWithLifecycle() + WalletBackupContent( + state = state, + modifier = modifier, + ) + } + + @AssistedFactory + interface Factory : WalletBackupComponent.Factory { + override fun create( + context: AppComponentContext, + params: WalletBackupComponent.Params, + ): DefaultWalletBackupComponent + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/di/WalletBackupModule.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/di/WalletBackupModule.kt new file mode 100644 index 0000000000..befb8e70c7 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/di/WalletBackupModule.kt @@ -0,0 +1,27 @@ +package com.tangem.features.hotwallet.walletbackup.di + +import com.tangem.core.decompose.model.Model +import com.tangem.features.hotwallet.WalletBackupComponent +import com.tangem.features.hotwallet.walletbackup.component.DefaultWalletBackupComponent +import com.tangem.features.hotwallet.walletbackup.model.WalletBackupModel +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 interface WalletBackupModule { + + @Binds + @IntoMap + @ClassKey(WalletBackupModel::class) + fun bindWalletBackupModel(model: WalletBackupModel): Model + + @Binds + @Singleton + fun bindWalletBackupComponentFactory(factory: DefaultWalletBackupComponent.Factory): WalletBackupComponent.Factory +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt new file mode 100644 index 0000000000..be22d8cd38 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/entity/WalletBackupUM.kt @@ -0,0 +1,15 @@ +package com.tangem.features.hotwallet.walletbackup.entity + +internal data class WalletBackupUM( + val onBackClick: () -> Unit, + val recoveryPhraseStatus: BackupStatus, + val googleDriveStatus: BackupStatus, + val onRecoveryPhraseClick: () -> Unit, + val onGoogleDriveClick: () -> Unit, +) + +internal sealed class BackupStatus { + object Done : BackupStatus() + object ComingSoon : BackupStatus() + object NoBackup : BackupStatus() +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt new file mode 100644 index 0000000000..f85e281c17 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/model/WalletBackupModel.kt @@ -0,0 +1,54 @@ +package com.tangem.features.hotwallet.walletbackup.model + +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.decompose.navigation.Router +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.features.hotwallet.WalletBackupComponent +import com.tangem.features.hotwallet.walletbackup.entity.BackupStatus +import com.tangem.features.hotwallet.walletbackup.entity.WalletBackupUM +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.* +import javax.inject.Inject + +@ModelScoped +internal class WalletBackupModel @Inject constructor( + paramsContainer: ParamsContainer, + getWalletUseCase: GetUserWalletUseCase, + private val router: Router, + override val dispatchers: CoroutineDispatcherProvider, +) : Model() { + + private val params: WalletBackupComponent.Params = paramsContainer.require() + + val uiState: StateFlow + field = MutableStateFlow( + WalletBackupUM( + onBackClick = { router.pop() }, + recoveryPhraseStatus = BackupStatus.NoBackup, + googleDriveStatus = BackupStatus.ComingSoon, + onRecoveryPhraseClick = { }, + onGoogleDriveClick = { }, + ), + ) + + init { + getWalletUseCase.invokeFlow(params.userWalletId) + .map { it.getOrNull() } + .distinctUntilChanged() + .onEach { + updateBackupStatuses() + } + .launchIn(modelScope) + } + + private fun updateBackupStatuses() { + uiState.update { currentState -> + currentState.copy( + recoveryPhraseStatus = BackupStatus.NoBackup, + googleDriveStatus = BackupStatus.ComingSoon, + ) + } + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt new file mode 100644 index 0000000000..7d5ac986a4 --- /dev/null +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletbackup/ui/WalletBackupContent.kt @@ -0,0 +1,155 @@ +package com.tangem.features.hotwallet.walletbackup.ui + +import android.content.res.Configuration +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.appbar.AppBarWithBackButton +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.walletbackup.entity.BackupStatus +import com.tangem.features.hotwallet.walletbackup.entity.WalletBackupUM +import com.tangem.features.hotwallet.common.ui.OptionBlock +import com.tangem.core.ui.R +import com.tangem.features.hotwallet.common.ui.DISABLED_COLORS_ALPHA + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun WalletBackupContent(state: WalletBackupUM, modifier: Modifier = Modifier) { + Column( + modifier = modifier + .background(TangemTheme.colors.background.secondary) + .fillMaxSize() + .systemBarsPadding(), + ) { + AppBarWithBackButton( + text = stringResourceSafe(R.string.common_backup), + onBackClick = state.onBackClick, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp), + ) { + OptionBlock( + modifier = Modifier.fillMaxWidth(), + title = stringResourceSafe(R.string.hw_backup_seed_title), + description = stringResourceSafe(R.string.hw_backup_seed_description), + badge = { + BackupStatusBadge(status = state.recoveryPhraseStatus) + }, + onClick = state.onRecoveryPhraseClick, + enabled = true, + backgroundColor = TangemTheme.colors.background.primary, + ) + + OptionBlock( + modifier = Modifier.fillMaxWidth(), + title = stringResourceSafe(R.string.hw_backup_google_drive_title), + description = stringResourceSafe(R.string.hw_backup_google_drive_description), + badge = { + BackupStatusBadge(status = state.googleDriveStatus) + }, + onClick = state.onGoogleDriveClick, + enabled = state.googleDriveStatus != BackupStatus.ComingSoon, + backgroundColor = TangemTheme.colors.background.primary, + ) + } + } +} + +@Composable +private fun BackupStatusBadge(status: BackupStatus, modifier: Modifier = Modifier) { + val text = when (status) { + BackupStatus.Done -> stringResourceSafe(R.string.common_done) + BackupStatus.ComingSoon -> stringResourceSafe(R.string.common_coming_soon) + BackupStatus.NoBackup -> stringResourceSafe(R.string.hw_backup_no_backup) + } + + val backgroundColor by animateColorAsState( + targetValue = when (status) { + BackupStatus.Done -> TangemTheme.colors.text.accent.copy(alpha = 0.1f) + BackupStatus.ComingSoon -> TangemTheme.colors.control.unchecked.copy(DISABLED_COLORS_ALPHA) + BackupStatus.NoBackup -> TangemTheme.colors.text.warning.copy(alpha = 0.1f) + }, + ) + + val textColor by animateColorAsState( + targetValue = when (status) { + BackupStatus.Done -> TangemTheme.colors.text.accent + BackupStatus.ComingSoon -> TangemTheme.colors.text.secondary.copy(DISABLED_COLORS_ALPHA) + BackupStatus.NoBackup -> TangemTheme.colors.text.warning + }, + ) + + AnimatedContent(targetState = text) { text -> + Box( + modifier = modifier + .padding(horizontal = 4.dp) + .background( + color = backgroundColor, + shape = TangemTheme.shapes.roundedCorners8, + ) + .padding(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + text = text, + style = TangemTheme.typography.caption1, + color = textColor, + ) + } + } +} + +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun WalletBackupContentPreview(@PreviewParameter(WalletBackupUMProvider::class) state: WalletBackupUM) { + TangemThemePreview { + WalletBackupContent(state) + } +} + +private class WalletBackupUMProvider : CollectionPreviewParameterProvider( + collection = listOf( + WalletBackupUM( + recoveryPhraseStatus = BackupStatus.NoBackup, + googleDriveStatus = BackupStatus.ComingSoon, + onBackClick = {}, + onRecoveryPhraseClick = {}, + onGoogleDriveClick = {}, + ), + WalletBackupUM( + recoveryPhraseStatus = BackupStatus.NoBackup, + googleDriveStatus = BackupStatus.NoBackup, + onBackClick = {}, + onRecoveryPhraseClick = {}, + onGoogleDriveClick = {}, + ), + WalletBackupUM( + recoveryPhraseStatus = BackupStatus.Done, + googleDriveStatus = BackupStatus.Done, + onBackClick = {}, + onRecoveryPhraseClick = {}, + onGoogleDriveClick = {}, + ), + ), +) \ No newline at end of file diff --git a/features/wallet-settings/impl/build.gradle.kts b/features/wallet-settings/impl/build.gradle.kts index 2de59a0dba..0adf247700 100644 --- a/features/wallet-settings/impl/build.gradle.kts +++ b/features/wallet-settings/impl/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { implementation(projects.features.nft.api) implementation(projects.features.onboardingV2.api) implementation(projects.features.pushNotifications.api) + implementation(projects.features.hotWallet.api) /* Project - Core */ implementation(projects.core.decompose) diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt index 5e9614cd3a..023afb9685 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/component/preview/PreviewWalletSettingsComponent.kt @@ -36,6 +36,7 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent { onCheckedNotificationsChanged = {}, onNotificationsDescriptionClick = {}, isNotificationsPermissionGranted = false, + isHotWalletEnabled = false, ), requestPushNotificationsPermission = false, onPushNotificationPermissionGranted = {}, diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt index b6d2f0e7dd..f4ea875953 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt @@ -41,6 +41,7 @@ import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM import com.tangem.feature.walletsettings.entity.WalletSettingsUM import com.tangem.feature.walletsettings.impl.R import com.tangem.feature.walletsettings.utils.ItemsBuilder +import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.PersistentList @@ -72,6 +73,7 @@ internal class WalletSettingsModel @Inject constructor( private val setNotificationsEnabledUseCase: SetNotificationsEnabledUseCase, private val settingsManager: SettingsManager, private val permissionsRepository: PermissionRepository, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, ) : Model() { val params: WalletSettingsComponent.Params = paramsContainer.require() @@ -105,6 +107,7 @@ internal class WalletSettingsModel @Inject constructor( isNotificationsEnabled = notificationsEnabled, isNotificationsFeatureEnabled = notificationsToggles.isNotificationsEnabled, isNotificationsPermissionGranted = isNotificationsPermissionGranted(), + isHotWalletEnabled = hotWalletFeatureToggles.isHotWalletEnabled, ), ) } @@ -130,6 +133,7 @@ internal class WalletSettingsModel @Inject constructor( isNotificationsFeatureEnabled: Boolean, isNotificationsEnabled: Boolean, isNotificationsPermissionGranted: Boolean, + isHotWalletEnabled: Boolean, ): PersistentList = itemsBuilder.buildItems( userWalletId = userWallet.walletId, userWalletName = userWallet.name, @@ -167,6 +171,7 @@ internal class WalletSettingsModel @Inject constructor( isNotificationsPermissionGranted = isNotificationsPermissionGranted, onCheckedNotificationsChanged = ::onCheckedNotificationsChange, onNotificationsDescriptionClick = ::onNotificationsDescriptionClick, + isHotWalletEnabled = isHotWalletEnabled, ) private fun openRenameWalletDialog(userWallet: UserWallet, dialogNavigation: SlotNavigation) { diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt index 9a0c8c8971..1349f34906 100644 --- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt +++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/utils/ItemsBuilder.kt @@ -43,6 +43,7 @@ internal class ItemsBuilder @Inject constructor( renameWallet: () -> Unit, onLinkMoreCardsClick: () -> Unit, onReferralClick: () -> Unit, + isHotWalletEnabled: Boolean, ): PersistentList = persistentListOf() .add(buildNameItem(userWalletName, isRenameWalletAvailable, renameWallet)) .run { @@ -60,6 +61,7 @@ internal class ItemsBuilder @Inject constructor( isManageTokensAvailable = isManageTokensAvailable, onLinkMoreCardsClick = onLinkMoreCardsClick, onReferralClick = onReferralClick, + isHotWalletEnabled = isHotWalletEnabled, ), ) .addAll( @@ -137,6 +139,7 @@ internal class ItemsBuilder @Inject constructor( isManageTokensAvailable: Boolean, onLinkMoreCardsClick: () -> Unit, onReferralClick: () -> Unit, + isHotWalletEnabled: Boolean, ) = WalletSettingsItemUM.WithItems( id = "card", description = resourceReference(R.string.settings_card_settings_footer), @@ -166,6 +169,14 @@ internal class ItemsBuilder @Inject constructor( onClick = { router.push(AppRoute.CardSettings(userWalletId)) }, ).let(::add) + if (isHotWalletEnabled) { + BlockUM( + text = resourceReference(R.string.common_backup), + iconRes = R.drawable.ic_more_cards_24, + onClick = { router.push(AppRoute.WalletBackup(userWalletId)) }, + ).let(::add) + } + if (isReferralAvailable) { BlockUM( text = resourceReference(R.string.details_referral_title),