From 98ec93e259b9bc8d89b8f9c521ced90dd73891db Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 12 Jul 2024 15:46:47 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../ui/amountScreen/ui/SendDoneButtons.kt | 73 +++++++++++++++++++ .../components/inputrow/InputRowImageBase.kt | 3 +- .../inputrow/InputRowImageChevron.kt | 13 ++-- .../inputrow/InputRowImageSelector.kt | 6 +- .../com/tangem/core/ui/res/TangemDimens.kt | 2 +- .../GetExplorerTransactionUrlUseCase.kt | 1 - .../presentation/ui/SendNavigationButtons.kt | 43 +---------- features/staking/impl/build.gradle.kts | 1 + .../staking/impl/di/StakingRouterModule.kt | 7 +- .../impl/navigation/DefaultStakingRouter.kt | 10 ++- .../impl/navigation/InnerStakingRouter.kt | 2 +- .../impl/presentation/StakingFragment.kt | 11 ++- .../state/InnerConfirmationStakingState.kt | 7 ++ .../state/StakingStateController.kt | 2 +- .../presentation/state/StakingStateRouter.kt | 45 ++++-------- .../impl/presentation/state/StakingUiState.kt | 27 +++---- .../state/TransactionDoneState.kt | 14 ++++ .../impl/presentation/state/ValidatorState.kt | 21 +++++- ...ata.kt => ConfirmationStatePreviewData.kt} | 8 +- .../state/stub/StakingClickIntentsStub.kt | 4 + .../SetConfirmStateInProgressTransformer.kt | 25 ------- ... SetConfirmationStateAssentTransformer.kt} | 14 ++-- ...etConfirmationStateCompletedTransformer.kt | 60 +++++++++++++++ ...tConfirmationStateInProgressTransformer.kt | 27 +++++++ ...SetConfirmationStateLoadingTransformer.kt} | 12 +-- .../SetInitialDataStateTransformer.kt | 12 +-- .../ValidatorSelectChangeTransformer.kt | 6 +- ...ntent.kt => StakingConfirmationContent.kt} | 28 +++++-- .../ui/StakingNavigationButtons.kt | 51 +++++++++---- .../impl/presentation/ui/StakingScreen.kt | 15 ++-- .../ui/StakingValidatorListContent.kt | 4 +- .../presentation/ui/block/ValidatorBlock.kt | 2 + .../viewmodel/StakingClickIntents.kt | 4 + .../viewmodel/StakingViewModel.kt | 57 ++++++++++----- 34 files changed, 407 insertions(+), 210 deletions(-) create mode 100644 common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/SendDoneButtons.kt create mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerConfirmationStakingState.kt create mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/TransactionDoneState.kt rename features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/{ConfirmStakingStatePreviewData.kt => ConfirmationStatePreviewData.kt} (92%) delete mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateInProgressTransformer.kt rename features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/{SetConfirmStateConfirmTransformer.kt => SetConfirmationStateAssentTransformer.kt} (77%) create mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt create mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt rename features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/{SetConfirmStateLoadingTransformer.kt => SetConfirmationStateLoadingTransformer.kt} (74%) rename features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/{StakingConfirmContent.kt => StakingConfirmationContent.kt} (72%) diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/SendDoneButtons.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/SendDoneButtons.kt new file mode 100644 index 0000000000..8689591d9b --- /dev/null +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/SendDoneButtons.kt @@ -0,0 +1,73 @@ +package com.tangem.common.ui.amountScreen.ui + +import android.content.res.Configuration +import androidx.compose.animation.* +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.SecondaryButtonIconStart +import com.tangem.core.ui.components.SpacerW12 +import com.tangem.core.ui.extensions.shareText +import com.tangem.core.ui.res.TangemTheme +import com.tangem.common.ui.R +import com.tangem.core.ui.res.TangemThemePreview + +@Composable +fun SendDoneButtons( + txUrl: String, + onExploreClick: () -> Unit, + onShareClick: () -> Unit, + isVisible: Boolean, + modifier: Modifier = Modifier, +) { + val hapticFeedback = LocalHapticFeedback.current + val context = LocalContext.current + + AnimatedVisibility( + visible = isVisible && txUrl.isNotBlank(), + modifier = modifier, + enter = slideInVertically().plus(fadeIn()), + exit = slideOutVertically().plus(fadeOut()), + label = "Animate show sent state buttons", + ) { + Row(modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12)) { + SecondaryButtonIconStart( + text = stringResource(id = R.string.common_explore), + iconResId = R.drawable.ic_web_24, + onClick = onExploreClick, + modifier = Modifier.weight(1f), + ) + SpacerW12() + SecondaryButtonIconStart( + text = stringResource(id = R.string.common_share), + iconResId = R.drawable.ic_share_24, + onClick = { + hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) + context.shareText(txUrl) + onShareClick() + }, + modifier = Modifier.weight(1f), + ) + } + } +} + +@Preview(showBackground = true, widthDp = 328) +@Preview(showBackground = true, widthDp = 328, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun SendDoneButtons_Preview() { + TangemThemePreview { + SendDoneButtons( + txUrl = "txUrl", + onShareClick = {}, + onExploreClick = {}, + isVisible = true, + ) + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt index 871dccfd94..00213b0077 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageBase.kt @@ -30,8 +30,7 @@ internal fun InputRowImageBase( InputRowAsyncImage( imageUrl = imageUrl, modifier = Modifier - .size(TangemTheme.dimens.spacing36) - .padding(vertical = TangemTheme.dimens.size1), + .size(TangemTheme.dimens.spacing36), ) Column { Text( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageChevron.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageChevron.kt index 83fd0ccbf0..c341f3ceac 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageChevron.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageChevron.kt @@ -35,6 +35,7 @@ fun InputRowImageChevron( modifier: Modifier = Modifier, subtitleColor: Color = TangemTheme.colors.text.primary1, captionColor: Color = TangemTheme.colors.text.tertiary, + showChevron: Boolean = true, ) { InputRowImageBase( subtitle = subtitle, @@ -45,11 +46,13 @@ fun InputRowImageChevron( captionColor = captionColor, ) { SpacerWMax() - Icon( - painter = painterResource(id = R.drawable.ic_chevron_right_24), - tint = TangemTheme.colors.icon.informative, - contentDescription = null, - ) + if (showChevron) { + Icon( + painter = painterResource(id = R.drawable.ic_chevron_right_24), + tint = TangemTheme.colors.icon.informative, + contentDescription = null, + ) + } } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt index 9e672eb56b..5231d7f896 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/InputRowImageSelector.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.core.ui.R +import com.tangem.core.ui.components.SpacerWMax import com.tangem.core.ui.components.atoms.radiobutton.TangemRadioButton import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.annotatedReference @@ -65,13 +66,14 @@ fun InputRowImageSelector( ) .padding(TangemTheme.dimens.spacing12), ) { + SpacerWMax() TangemRadioButton(isSelected = isSelected, isEnabled = false, onClick = onSelect) } } //region preview -@Preview -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(widthDp = 328) +@Preview(widthDp = 328, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable private fun InputRowImageSelectorPreview( @PreviewParameter(InputRowImageSelectorPreviewDataProvider::class) data: InputRowImageSelectorPreviewData, diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 4d47c4bf0f..9b00a821e5 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -122,7 +122,7 @@ data class TangemDimens internal constructor( val spacing30: Dp = 30.dp, val spacing32: Dp = 32.dp, val spacing34: Dp = 34.dp, - val spacing36: Dp = 34.dp, + val spacing36: Dp = 36.dp, val spacing38: Dp = 38.dp, val spacing40: Dp = 40.dp, val spacing44: Dp = 44.dp, diff --git a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetExplorerTransactionUrlUseCase.kt b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetExplorerTransactionUrlUseCase.kt index cedb309901..991475bef2 100644 --- a/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetExplorerTransactionUrlUseCase.kt +++ b/domain/txhistory/src/main/kotlin/com/tangem/domain/txhistory/usecase/GetExplorerTransactionUrlUseCase.kt @@ -11,7 +11,6 @@ import com.tangem.domain.wallets.models.UserWalletId class GetExplorerTransactionUrlUseCase( private val repository: TxHistoryRepository, ) { - @Deprecated("Replace with invoke [UserWalletId, Network]") operator fun invoke(txHash: String, networkId: Network.ID): Either { return either { catch( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt index e47d869fb6..3e676181c9 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt @@ -16,17 +16,16 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.hapticfeedback.HapticFeedbackType -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import com.tangem.common.ui.amountScreen.models.AmountState +import com.tangem.common.ui.amountScreen.ui.SendDoneButtons import com.tangem.common.ui.amountScreen.utils.getCryptoReference import com.tangem.common.ui.amountScreen.utils.getFiatString import com.tangem.core.ui.R import com.tangem.core.ui.components.Keyboard -import com.tangem.core.ui.components.SecondaryButtonIconStart import com.tangem.core.ui.components.SpacerW12 import com.tangem.core.ui.components.buttons.common.TangemButton import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition @@ -220,46 +219,6 @@ private fun SendingText( } } -@Composable -private fun SendDoneButtons( - txUrl: String, - onExploreClick: () -> Unit, - onShareClick: () -> Unit, - isVisible: Boolean, - modifier: Modifier = Modifier, -) { - val hapticFeedback = LocalHapticFeedback.current - val context = LocalContext.current - - AnimatedVisibility( - visible = isVisible && txUrl.isNotBlank(), - modifier = modifier, - enter = slideInVertically().plus(fadeIn()), - exit = slideOutVertically().plus(fadeOut()), - label = "Animate show sent state buttons", - ) { - Row(modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12)) { - SecondaryButtonIconStart( - text = stringResource(id = R.string.common_explore), - iconResId = R.drawable.ic_web_24, - onClick = onExploreClick, - modifier = Modifier.weight(1f), - ) - SpacerW12() - SecondaryButtonIconStart( - text = stringResource(id = R.string.common_share), - iconResId = R.drawable.ic_share_24, - onClick = { - hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) - context.shareText(txUrl) - onShareClick() - }, - modifier = Modifier.weight(1f), - ) - } - } -} - private fun getButtonData( uiState: SendUiState, currentState: SendUiCurrentScreen, diff --git a/features/staking/impl/build.gradle.kts b/features/staking/impl/build.gradle.kts index 8325def273..15213f79d6 100644 --- a/features/staking/impl/build.gradle.kts +++ b/features/staking/impl/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { implementation(projects.domain.legacy) implementation(projects.domain.models) implementation(projects.domain.transaction) + implementation(projects.domain.txhistory) /** Common */ implementation(projects.common.ui) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingRouterModule.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingRouterModule.kt index c351d87a6e..c64b0dd4f2 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingRouterModule.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingRouterModule.kt @@ -1,5 +1,6 @@ package com.tangem.features.staking.impl.di +import com.tangem.core.navigation.url.UrlOpener import com.tangem.features.staking.impl.navigation.DefaultStakingRouter import com.tangem.features.staking.api.navigation.StakingRouter import dagger.Module @@ -17,7 +18,9 @@ internal object StakingRouterModule { @Provides @ActivityScoped - fun provideStakingRouter(): StakingRouter { - return DefaultStakingRouter() + fun provideStakingRouter(urlOpener: UrlOpener): StakingRouter { + return DefaultStakingRouter( + urlOpener = urlOpener, + ) } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt index 351a4a7a28..464d28694e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/DefaultStakingRouter.kt @@ -1,9 +1,15 @@ package com.tangem.features.staking.impl.navigation import androidx.fragment.app.Fragment +import com.tangem.core.navigation.url.UrlOpener import com.tangem.features.staking.impl.presentation.StakingFragment -internal class DefaultStakingRouter : InnerStakingRouter { - +internal class DefaultStakingRouter( + private val urlOpener: UrlOpener, +) : InnerStakingRouter { override fun getEntryFragment(): Fragment = StakingFragment.create() + + override fun openUrl(url: String) { + urlOpener.openUrl(url) + } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/InnerStakingRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/InnerStakingRouter.kt index dd7187d902..d4197489fb 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/InnerStakingRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/navigation/InnerStakingRouter.kt @@ -4,5 +4,5 @@ import com.tangem.features.staking.api.navigation.StakingRouter interface InnerStakingRouter : StakingRouter { - // TODO staking + fun openUrl(url: String) } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/StakingFragment.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/StakingFragment.kt index 64b167ead5..cb590bcb4c 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/StakingFragment.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/StakingFragment.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.fragment.app.viewModels import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.UiDependencies import com.tangem.core.ui.screen.ComposeFragment @@ -15,7 +16,6 @@ import com.tangem.features.staking.impl.presentation.state.StakingStateRouter import com.tangem.features.staking.impl.presentation.ui.StakingScreen import com.tangem.features.staking.impl.presentation.viewmodel.StakingViewModel import dagger.hilt.android.AndroidEntryPoint -import java.lang.ref.WeakReference import javax.inject.Inject /** @@ -28,7 +28,10 @@ internal class StakingFragment : ComposeFragment() { override lateinit var uiDependencies: UiDependencies @Inject - lateinit var router: StakingRouter + lateinit var stakingRouter: StakingRouter + + @Inject + lateinit var appRouter: AppRouter @Inject lateinit var stateController: StakingStateController @@ -38,7 +41,7 @@ internal class StakingFragment : ComposeFragment() { private val viewModel by viewModels() private val innerStakingRouter: InnerStakingRouter - get() = requireNotNull(router as? InnerStakingRouter) { + get() = requireNotNull(stakingRouter as? InnerStakingRouter) { "innerStakingRouter should be instance of InnerStakingRouter" } @@ -49,7 +52,7 @@ internal class StakingFragment : ComposeFragment() { viewModel.setRouter( innerStakingRouter, StakingStateRouter( - fragmentManager = WeakReference(parentFragmentManager), + appRouter = appRouter, stateController = stateController, ), ) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerConfirmationStakingState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerConfirmationStakingState.kt new file mode 100644 index 0000000000..babc93a2dd --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/InnerConfirmationStakingState.kt @@ -0,0 +1,7 @@ +package com.tangem.features.staking.impl.presentation.state + +enum class InnerConfirmationStakingState { + ASSENT, + IN_PROGRESS, + COMPLETED, +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt index d62526b9a8..f263b18a14 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt @@ -40,7 +40,7 @@ internal class StakingStateController @Inject constructor() { initialInfoState = StakingStates.InitialInfoState.Empty(), amountState = AmountState.Empty(), rewardsValidatorsState = StakingStates.RewardsValidatorsState.Empty(), - confirmStakingState = StakingStates.ConfirmStakingState.Empty(), + confirmationState = StakingStates.ConfirmationState.Empty(), isBalanceHidden = false, event = consumedEvent(), bottomSheetConfig = null, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt index 5f277ce4a4..d3edfd4322 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt @@ -1,49 +1,37 @@ package com.tangem.features.staking.impl.presentation.state -import androidx.fragment.app.FragmentManager -import java.lang.ref.WeakReference +import com.tangem.common.routing.AppRouter internal class StakingStateRouter( - private val fragmentManager: WeakReference, + private val appRouter: AppRouter, private val stateController: StakingStateController, ) { - private fun closeStaking() { - fragmentManager.get()?.popBackStack() + fun onBackClick() { + appRouter.pop() stateController.clear() } - fun onBackClick(isSuccess: Boolean = false) { - val type = stateController.uiState.value.currentStep - when { - isSuccess -> closeStaking() - else -> when (type) { - StakingStep.Amount -> showInitial() - StakingStep.Confirm -> showAmount() - else -> closeStaking() - } - } - } - fun onNextClick() { when (stateController.uiState.value.currentStep) { StakingStep.InitialInfo -> showAmount() StakingStep.RewardsValidators, StakingStep.Validators, StakingStep.Amount, - -> showConfirm() - StakingStep.Confirm -> showSuccess() - StakingStep.Success -> closeStaking() + -> showConfirmation() + StakingStep.Confirmation -> { + // TODO staking handle + } } } fun onPrevClick() { when (stateController.uiState.value.currentStep) { + StakingStep.InitialInfo -> onBackClick() StakingStep.Amount -> showInitial() - StakingStep.Confirm -> showAmount() - StakingStep.Success -> closeStaking() - StakingStep.Validators -> showConfirm() - else -> closeStaking() + StakingStep.Confirmation -> showAmount() + StakingStep.Validators -> showConfirmation() + StakingStep.RewardsValidators -> showInitial() } } @@ -63,12 +51,7 @@ internal class StakingStateRouter( stateController.update { it.copy(currentStep = StakingStep.Validators) } } - fun showConfirm() { - stateController.update { it.copy(currentStep = StakingStep.Confirm) } - } - - fun showSuccess() { - // stateController.update { it.copy(currentStep = StakingStep.Success) } - // TODO staking [REDACTED_TASK_KEY] + fun showConfirmation() { + stateController.update { it.copy(currentStep = StakingStep.Confirmation) } } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt index 65fe669de8..cd1e65b946 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt @@ -20,7 +20,7 @@ internal data class StakingUiState( val initialInfoState: StakingStates.InitialInfoState, val amountState: AmountState, val rewardsValidatorsState: StakingStates.RewardsValidatorsState, - val confirmStakingState: StakingStates.ConfirmStakingState, + val confirmationState: StakingStates.ConfirmationState, val isBalanceHidden: Boolean, val bottomSheetConfig: TangemBottomSheetConfig?, val event: StateEvent, @@ -29,11 +29,11 @@ internal data class StakingUiState( fun copyWrapped( initialInfoState: StakingStates.InitialInfoState = this.initialInfoState, amountState: AmountState = this.amountState, - confirmStakingState: StakingStates.ConfirmStakingState = this.confirmStakingState, + confirmationState: StakingStates.ConfirmationState = this.confirmationState, ): StakingUiState = copy( initialInfoState = initialInfoState, amountState = amountState, - confirmStakingState = confirmStakingState, + confirmationState = confirmationState, ) } @@ -74,27 +74,21 @@ internal sealed class StakingStates { ) : RewardsValidatorsState() } - /** Confirm state */ - sealed class ConfirmStakingState : StakingStates() { + /** Confirmation state */ + sealed class ConfirmationState : StakingStates() { data class Data( override val isPrimaryButtonEnabled: Boolean, + val innerState: InnerConfirmationStakingState, val feeState: FeeState, val validatorState: ValidatorState, val notifications: ImmutableList, val footerText: String, - val innerState: InnerConfirmStakingState, - ) : ConfirmStakingState() { - - enum class InnerConfirmStakingState { - CONFIRM, - IN_PROGRESS, - SUCCESS, - } - } + val transactionDoneState: TransactionDoneState, + ) : ConfirmationState() data class Empty( override val isPrimaryButtonEnabled: Boolean = false, - ) : ConfirmStakingState() + ) : ConfirmationState() } } @@ -102,7 +96,6 @@ enum class StakingStep { InitialInfo, RewardsValidators, Amount, - Confirm, + Confirmation, Validators, - Success, } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/TransactionDoneState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/TransactionDoneState.kt new file mode 100644 index 0000000000..3af58c716f --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/TransactionDoneState.kt @@ -0,0 +1,14 @@ +package com.tangem.features.staking.impl.presentation.state + +import androidx.compose.runtime.Immutable + +@Immutable +internal sealed class TransactionDoneState { + + data class Content( + val timestamp: Long, + val txUrl: String, + ) : TransactionDoneState() + + data object Empty : TransactionDoneState() +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt index d99ed81d8e..0510d12380 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/ValidatorState.kt @@ -6,12 +6,29 @@ import com.tangem.domain.staking.model.Yield @Immutable internal sealed class ValidatorState { + abstract val isClickable: Boolean + data class Content( + override val isClickable: Boolean, val chosenValidator: Yield.Validator, val availableValidators: List, ) : ValidatorState() - data object Loading : ValidatorState() + data object Loading : ValidatorState() { + override val isClickable: Boolean + get() = false + } - data object Error : ValidatorState() + data object Error : ValidatorState() { + override val isClickable: Boolean + get() = false + } + + fun copySealed(isClickable: Boolean): ValidatorState { + return if (this is Content) { + copy(isClickable = isClickable) + } else { + this + } + } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt similarity index 92% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt index 34916ee421..3d1e0fcebf 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmStakingStatePreviewData.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/previewdata/ConfirmationStatePreviewData.kt @@ -12,7 +12,7 @@ import com.tangem.features.staking.impl.presentation.state.ValidatorState import kotlinx.collections.immutable.persistentListOf import java.math.BigDecimal -internal object ConfirmStakingStatePreviewData { +internal object ConfirmationStatePreviewData { private val validatorList = listOf( Yield.Validator( @@ -62,8 +62,9 @@ internal object ConfirmStakingStatePreviewData { ), ) - val confirmStakingState = StakingStates.ConfirmStakingState.Data( + val assentStakingState = StakingStates.ConfirmationState.Data( isPrimaryButtonEnabled = true, + innerState = InnerConfirmationStakingState.ASSENT, feeState = FeeState.Content( fee = fee, rate = BigDecimal.ONE, @@ -72,6 +73,7 @@ internal object ConfirmStakingStatePreviewData { isFeeConvertibleToFiat = true, ), validatorState = ValidatorState.Content( + isClickable = true, chosenValidator = validatorList[0], availableValidators = validatorList, ), @@ -82,6 +84,6 @@ internal object ConfirmStakingStatePreviewData { days = 2, ), ), - innerState = StakingStates.ConfirmStakingState.Data.InnerConfirmStakingState.CONFIRM, + transactionDoneState = TransactionDoneState.Empty, ) } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt index 6320dce75c..64e66f66d8 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/stub/StakingClickIntentsStub.kt @@ -31,4 +31,8 @@ object StakingClickIntentsStub : StakingClickIntents { override fun openRewardsValidators() {} override fun selectRewardValidator(rewardValue: String) {} + + override fun onExploreClick() {} + + override fun onShareClick() {} } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateInProgressTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateInProgressTransformer.kt deleted file mode 100644 index edad01bfea..0000000000 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateInProgressTransformer.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.tangem.features.staking.impl.presentation.state.transformers - -import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.state.StakingUiState -import com.tangem.utils.transformer.Transformer - -internal class SetConfirmStateInProgressTransformer : Transformer { - - override fun transform(prevState: StakingUiState): StakingUiState { - return prevState.copy( - confirmStakingState = prevState.confirmStakingState.copyWrapped(), - ) - } - - private fun StakingStates.ConfirmStakingState.copyWrapped(): StakingStates.ConfirmStakingState { - return if (this is StakingStates.ConfirmStakingState.Data) { - copy( - isPrimaryButtonEnabled = false, - innerState = StakingStates.ConfirmStakingState.Data.InnerConfirmStakingState.IN_PROGRESS, - ) - } else { - this - } - } -} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateConfirmTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateAssentTransformer.kt similarity index 77% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateConfirmTransformer.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateAssentTransformer.kt index f058a772c3..df4fc57ae3 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateConfirmTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateAssentTransformer.kt @@ -10,9 +10,10 @@ import com.tangem.features.staking.impl.presentation.state.StakingUiState import com.tangem.utils.Provider import com.tangem.utils.transformer.Transformer import com.tangem.blockchain.common.Amount +import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState @Suppress("UnusedPrivateMember") -internal class SetConfirmStateConfirmTransformer( +internal class SetConfirmationStateAssentTransformer( private val appCurrencyProvider: Provider, private val cryptoCurrencyStatusProvider: Provider, private val stakingGasEstimate: StakingGasEstimate, @@ -20,15 +21,16 @@ internal class SetConfirmStateConfirmTransformer( override fun transform(prevState: StakingUiState): StakingUiState { return prevState.copy( - confirmStakingState = prevState.confirmStakingState.copyWrapped(stakingGasEstimate), + confirmationState = prevState.confirmationState.copyWrapped(stakingGasEstimate), ) } - private fun StakingStates.ConfirmStakingState.copyWrapped( + private fun StakingStates.ConfirmationState.copyWrapped( gasEstimate: StakingGasEstimate, - ): StakingStates.ConfirmStakingState { - if (this is StakingStates.ConfirmStakingState.Data) { + ): StakingStates.ConfirmationState { + if (this is StakingStates.ConfirmationState.Data) { return copy( + innerState = InnerConfirmationStakingState.ASSENT, feeState = FeeState.Content( fee = Fee.Common( Amount( @@ -42,8 +44,8 @@ internal class SetConfirmStateConfirmTransformer( appCurrency = appCurrencyProvider(), isFeeApproximate = false, ), + validatorState = validatorState.copySealed(isClickable = true), isPrimaryButtonEnabled = true, - innerState = StakingStates.ConfirmStakingState.Data.InnerConfirmStakingState.CONFIRM, ) } else { return this diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt new file mode 100644 index 0000000000..f83c870fc6 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateCompletedTransformer.kt @@ -0,0 +1,60 @@ +package com.tangem.features.staking.impl.presentation.state.transformers + +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.transaction.Fee +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.staking.model.transaction.StakingGasEstimate +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.features.staking.impl.presentation.state.* +import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.features.staking.impl.presentation.state.TransactionDoneState +import com.tangem.utils.Provider +import com.tangem.utils.transformer.Transformer + +internal class SetConfirmationStateCompletedTransformer( + private val appCurrencyProvider: Provider, + private val cryptoCurrencyStatusProvider: Provider, + private val stakingGasEstimate: StakingGasEstimate, + private val txUrl: String, +) : Transformer { + + override fun transform(prevState: StakingUiState): StakingUiState { + return prevState.copy( + confirmationState = prevState.confirmationState.copyWrapped(stakingGasEstimate), + ) + } + + private fun StakingStates.ConfirmationState.copyWrapped( + gasEstimate: StakingGasEstimate, + ): StakingStates.ConfirmationState { + if (this is StakingStates.ConfirmationState.Data) { + return copy( + isPrimaryButtonEnabled = true, + innerState = InnerConfirmationStakingState.COMPLETED, + feeState = FeeState.Content( + fee = Fee.Common( + Amount( + currencySymbol = gasEstimate.token.symbol, + value = gasEstimate.amount, + decimals = gasEstimate.token.decimals, + ), + ), + rate = cryptoCurrencyStatusProvider().value.fiatRate, + isFeeConvertibleToFiat = cryptoCurrencyStatusProvider().currency.network.hasFiatFeeRate, + appCurrency = appCurrencyProvider(), + isFeeApproximate = false, + ), + validatorState = validatorState.copySealed( + isClickable = false, + ), + transactionDoneState = TransactionDoneState.Content( + timestamp = System.currentTimeMillis(), + txUrl = txUrl, + ), + ) + } else { + return this + } + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt new file mode 100644 index 0000000000..e17aad84b4 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInProgressTransformer.kt @@ -0,0 +1,27 @@ +package com.tangem.features.staking.impl.presentation.state.transformers + +import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState +import com.tangem.features.staking.impl.presentation.state.StakingStates +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.utils.transformer.Transformer + +internal class SetConfirmationStateInProgressTransformer : Transformer { + + override fun transform(prevState: StakingUiState): StakingUiState { + return prevState.copy( + confirmationState = prevState.confirmationState.copyWrapped(), + ) + } + + private fun StakingStates.ConfirmationState.copyWrapped(): StakingStates.ConfirmationState { + return if (this is StakingStates.ConfirmationState.Data) { + copy( + isPrimaryButtonEnabled = false, + innerState = InnerConfirmationStakingState.IN_PROGRESS, + validatorState = validatorState.copySealed(isClickable = false), + ) + } else { + this + } + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateLoadingTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt similarity index 74% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateLoadingTransformer.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt index 838a5db5cd..0b12d8b8f8 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmStateLoadingTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateLoadingTransformer.kt @@ -10,20 +10,22 @@ import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.persistentListOf @Suppress("UnusedPrivateMember") -internal class SetConfirmStateLoadingTransformer( +internal class SetConfirmationStateLoadingTransformer( private val yield: Yield, ) : Transformer { override fun transform(prevState: StakingUiState): StakingUiState { - val possibleConfirmStakingState = prevState.confirmStakingState as? StakingStates.ConfirmStakingState.Data - val possibleValidatorState = possibleConfirmStakingState?.validatorState as? ValidatorState.Content + val possibleConfirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data + val possibleValidatorState = possibleConfirmationState?.validatorState as? ValidatorState.Content val chosenValidator = possibleValidatorState?.chosenValidator ?: yield.validators[0] return prevState.copy( - confirmStakingState = StakingStates.ConfirmStakingState.Data( + confirmationState = StakingStates.ConfirmationState.Data( isPrimaryButtonEnabled = false, + innerState = InnerConfirmationStakingState.ASSENT, feeState = FeeState.Loading, validatorState = ValidatorState.Content( + isClickable = false, chosenValidator = chosenValidator, availableValidators = yield.validators, ), @@ -34,7 +36,7 @@ internal class SetConfirmStateLoadingTransformer( ), ), footerText = "", - innerState = StakingStates.ConfirmStakingState.Data.InnerConfirmStakingState.CONFIRM, + transactionDoneState = TransactionDoneState.Empty, ), ) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index e66d509f0d..3cc9baa334 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.features.staking.impl.presentation.state.transformers +import com.tangem.common.extensions.remove import com.tangem.common.ui.amountScreen.converters.AmountStateConverter import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter @@ -20,7 +21,7 @@ import com.tangem.features.staking.impl.presentation.state.StakingUiState import com.tangem.features.staking.impl.presentation.state.ValidatorState import com.tangem.features.staking.impl.presentation.state.converters.RewardsValidatorStateConverter import com.tangem.features.staking.impl.presentation.state.converters.YieldBalancesConverter -import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData +import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmationStatePreviewData import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents import com.tangem.utils.Provider import com.tangem.utils.extensions.orZero @@ -61,7 +62,7 @@ internal class SetInitialDataStateTransformer( currentStep = StakingStep.InitialInfo, initialInfoState = createInitialInfoState(), amountState = createInitialAmountState(), - confirmStakingState = createInitialConfirmationState(), + confirmationState = createInitialConfirmationState(), rewardsValidatorsState = rewardsValidatorStateConverter.convert(Unit), bottomSheetConfig = null, ) @@ -98,9 +99,10 @@ internal class SetInitialDataStateTransformer( return amountStateConverter.convert("") } - private fun createInitialConfirmationState(): StakingStates.ConfirmStakingState { - return ConfirmStakingStatePreviewData.confirmStakingState.copy( + private fun createInitialConfirmationState(): StakingStates.ConfirmationState { + return ConfirmationStatePreviewData.assentStakingState.copy( validatorState = ValidatorState.Content( + isClickable = true, chosenValidator = yield.validators.first(), availableValidators = yield.validators, ), @@ -116,7 +118,7 @@ internal class SetInitialDataStateTransformer( val formattedMinApr = BigDecimalFormatter.formatPercent( percent = minApr, useAbsoluteValue = true, - ) + ).remove("%") val formattedMaxApr = BigDecimalFormatter.formatPercent( percent = maxApr, useAbsoluteValue = true, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt index b72f227693..714a89de67 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/validator/ValidatorSelectChangeTransformer.kt @@ -10,11 +10,11 @@ internal class ValidatorSelectChangeTransformer( private val selectedValidator: Yield.Validator, ) : Transformer { override fun transform(prevState: StakingUiState): StakingUiState { - val confirmState = prevState.confirmStakingState as? StakingStates.ConfirmStakingState.Data ?: return prevState - val validatorState = confirmState.validatorState as? ValidatorState.Content ?: return prevState + val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState + val validatorState = confirmationState.validatorState as? ValidatorState.Content ?: return prevState return prevState.copy( - confirmStakingState = confirmState.copy( + confirmationState = confirmationState.copy( validatorState = validatorState.copy( chosenValidator = selectedValidator, ), diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt similarity index 72% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt index be8589fa2f..98f42fccf2 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt @@ -1,6 +1,7 @@ package com.tangem.features.staking.impl.presentation.ui import android.content.res.Configuration +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -14,23 +15,26 @@ import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData import com.tangem.common.ui.amountScreen.ui.AmountBlock import com.tangem.core.ui.components.SpacerHMax +import com.tangem.core.ui.components.transactions.TransactionDoneTitle import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData +import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmationStatePreviewData import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub import com.tangem.features.staking.impl.presentation.ui.block.NotificationsBlock import com.tangem.features.staking.impl.presentation.ui.block.StakingFeeBlock import com.tangem.features.staking.impl.presentation.ui.block.ValidatorBlock import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.R +import com.tangem.features.staking.impl.presentation.state.TransactionDoneState @Composable -internal fun StakingConfirmContent( +internal fun StakingConfirmationContent( amountState: AmountState, - state: StakingStates.ConfirmStakingState, + state: StakingStates.ConfirmationState, clickIntents: StakingClickIntents, ) { - if (state !is StakingStates.ConfirmStakingState.Data) return + if (state !is StakingStates.ConfirmationState.Data) return Column( modifier = Modifier @@ -40,6 +44,16 @@ internal fun StakingConfirmContent( .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), ) { + AnimatedVisibility( + visible = state.transactionDoneState is TransactionDoneState.Content, + modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing12), + ) { + val transactionDoneStateContent = state.transactionDoneState as TransactionDoneState.Content + TransactionDoneTitle( + titleRes = R.string.sent_transaction_sent_title, + date = transactionDoneStateContent.timestamp, + ) + } AmountBlock( amountState = amountState, isClickDisabled = true, @@ -68,12 +82,12 @@ private fun FooterText(text: String) { @Preview(widthDp = 360, showBackground = true) @Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -private fun Preview_StakingConfirmContent() { +private fun Preview_StakingConfirmationContent() { TangemThemePreview { Column(Modifier.background(TangemTheme.colors.background.primary)) { - StakingConfirmContent( + StakingConfirmationContent( amountState = AmountStatePreviewData.amountState, - state = ConfirmStakingStatePreviewData.confirmStakingState, + state = ConfirmationStatePreviewData.assentStakingState, clickIntents = StakingClickIntentsStub, ) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt index 1ee7aca2ac..695d1a3bb7 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingNavigationButtons.kt @@ -17,19 +17,22 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import com.tangem.common.ui.amountScreen.ui.SendDoneButtons import com.tangem.core.ui.R import com.tangem.core.ui.components.SpacerW12 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.TangemButtonsDefaults import com.tangem.core.ui.res.TangemTheme -import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState +import com.tangem.features.staking.impl.presentation.state.* import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.state.StakingStep import com.tangem.features.staking.impl.presentation.state.StakingUiState @Composable internal fun StakingNavigationButtons(uiState: StakingUiState, modifier: Modifier = Modifier) { + val confirmInnerState = (uiState.confirmationState as? StakingStates.ConfirmationState.Data)?.innerState + val isSuccessState = confirmInnerState == InnerConfirmationStakingState.COMPLETED + Column( modifier = modifier .padding( @@ -38,6 +41,15 @@ internal fun StakingNavigationButtons(uiState: StakingUiState, modifier: Modifie bottom = TangemTheme.dimens.spacing16, ), ) { + val confirmationDataState = uiState.confirmationState as? StakingStates.ConfirmationState.Data + val transactionDoneState = confirmationDataState?.transactionDoneState as? TransactionDoneState.Content + + SendDoneButtons( + txUrl = transactionDoneState?.txUrl.orEmpty(), + onExploreClick = uiState.clickIntents::onExploreClick, + onShareClick = uiState.clickIntents::onShareClick, + isVisible = isSuccessState, + ) StakingNavigationButton( uiState = uiState, modifier = Modifier, @@ -50,13 +62,19 @@ private fun StakingNavigationButton(uiState: StakingUiState, modifier: Modifier val hapticFeedback = LocalHapticFeedback.current val isButtonsVisible = isPrevButtonVisible(uiState.currentStep) - val isStakingState = uiState.currentStep == StakingStep.Confirm + + val innerConfirmState = (uiState.confirmationState as? StakingStates.ConfirmationState.Data)?.innerState + val isInProgressInnerState = innerConfirmState == InnerConfirmationStakingState.IN_PROGRESS + val isInAssentInnerState = innerConfirmState == InnerConfirmationStakingState.ASSENT + + val showTangemIcon = uiState.currentStep == StakingStep.Confirmation && + (isInProgressInnerState || isInAssentInnerState) val (buttonTextId, buttonClick) = getButtonData( currentState = uiState, ) val isButtonEnabled = isButtonEnabled(uiState) - val buttonIcon = if (isStakingState) { + val buttonIcon = if (showTangemIcon) { TangemButtonIconPosition.End(R.drawable.ic_tangem_24) } else { TangemButtonIconPosition.None @@ -82,7 +100,6 @@ private fun StakingNavigationButton(uiState: StakingUiState, modifier: Modifier SpacerW12() } } - AnimatedVisibility( visible = buttonClick != null, enter = fadeIn(), @@ -93,7 +110,7 @@ private fun StakingNavigationButton(uiState: StakingUiState, modifier: Modifier icon = buttonIcon, enabled = isButtonEnabled && buttonClick != null, onClick = { - if (isStakingState) hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) + if (showTangemIcon) hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) if (buttonClick != null) buttonClick() }, showProgress = false, @@ -116,18 +133,27 @@ private fun getButtonData(currentState: StakingUiState): Pair Unit)? } StakingStep.Amount, -> R.string.common_next to currentState.clickIntents::onNextClick - StakingStep.Confirm -> R.string.common_stake to currentState.clickIntents::onNextClick + StakingStep.Confirmation -> { + val confirmationState = currentState.confirmationState + if (confirmationState is StakingStates.ConfirmationState.Data) { + if (confirmationState.innerState == InnerConfirmationStakingState.COMPLETED) { + R.string.common_close to currentState.clickIntents::onBackClick + } else { + R.string.common_stake to currentState.clickIntents::onNextClick + } + } else { + R.string.common_close to currentState.clickIntents::onBackClick + } + } StakingStep.Validators -> R.string.common_continue to currentState.clickIntents::onNextClick - StakingStep.Success -> R.string.common_close to currentState.clickIntents::onBackClick - else -> R.string.common_next to null + StakingStep.RewardsValidators -> R.string.common_next to null } } private fun isPrevButtonVisible(step: StakingStep): Boolean = when (step) { StakingStep.InitialInfo, StakingStep.RewardsValidators, - StakingStep.Confirm, - StakingStep.Success, + StakingStep.Confirmation, -> false StakingStep.Amount, StakingStep.Validators, @@ -138,9 +164,8 @@ private fun isButtonEnabled(uiState: StakingUiState): Boolean { return when (uiState.currentStep) { StakingStep.InitialInfo -> uiState.initialInfoState.isPrimaryButtonEnabled StakingStep.Amount -> uiState.amountState.isPrimaryButtonEnabled - StakingStep.Confirm -> uiState.confirmStakingState.isPrimaryButtonEnabled + StakingStep.Confirmation -> uiState.confirmationState.isPrimaryButtonEnabled StakingStep.RewardsValidators -> uiState.rewardsValidatorsState.isPrimaryButtonEnabled - StakingStep.Success -> true StakingStep.Validators -> true } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt index 1b92f7fcea..e1b08be7ac 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingScreen.kt @@ -67,15 +67,13 @@ private fun SendAppBar(uiState: StakingUiState) { StakingStep.InitialInfo, StakingStep.RewardsValidators, StakingStep.Validators, - StakingStep.Confirm, + StakingStep.Confirmation, -> stringResource(id = R.string.common_stake) - StakingStep.Success -> "" } val backIcon = when (uiState.currentStep) { StakingStep.Amount, StakingStep.Validators, - StakingStep.Confirm, - StakingStep.Success, + StakingStep.Confirmation, -> { R.drawable.ic_close_24 } @@ -153,20 +151,19 @@ private fun StakingScreenContent(uiState: StakingUiState, modifier: Modifier = M isBalanceHiding = uiState.isBalanceHidden, clickIntents = uiState.clickIntents, ) - StakingStep.Confirm -> StakingConfirmContent( + StakingStep.Confirmation -> StakingConfirmationContent( amountState = uiState.amountState, - state = uiState.confirmStakingState, + state = uiState.confirmationState, clickIntents = uiState.clickIntents, ) StakingStep.Validators -> { - val confirmState = uiState.confirmStakingState - if (confirmState !is StakingStates.ConfirmStakingState.Data) return@AnimatedContent + val confirmState = uiState.confirmationState + if (confirmState !is StakingStates.ConfirmationState.Data) return@AnimatedContent StakingValidatorListContent( state = confirmState.validatorState, clickIntents = uiState.clickIntents, ) } - else -> TODO() } } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt index 1d6e05103d..743979fa67 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt @@ -27,7 +27,7 @@ import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.ValidatorState -import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmStakingStatePreviewData +import com.tangem.features.staking.impl.presentation.state.previewdata.ConfirmationStatePreviewData import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents import java.math.BigDecimal @@ -124,6 +124,6 @@ private fun StakingValidatorListContent_Preview( private class StakingValidatorListContentPreviewProvider : PreviewParameterProvider { override val values: Sequence - get() = sequenceOf(ConfirmStakingStatePreviewData.confirmStakingState.validatorState) + get() = sequenceOf(ConfirmationStatePreviewData.assentStakingState.validatorState) } // endregion \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt index 4cee3bcba5..ffd1d0c966 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt @@ -35,6 +35,7 @@ internal fun ValidatorBlock(validatorState: ValidatorState, onClick: () -> Unit) .clip(TangemTheme.shapes.roundedCornersXMedium) .background(TangemTheme.colors.background.action) .clickable( + enabled = validatorState.isClickable, interactionSource = remember { MutableInteractionSource() }, indication = rememberRipple(), onClick = onClick, @@ -63,6 +64,7 @@ internal fun ValidatorBlock(validatorState: ValidatorState, onClick: () -> Unit) ), ), imageUrl = validatorState.chosenValidator.image.orEmpty(), + showChevron = validatorState.isClickable, ) } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt index 62f5fc6c5c..0173545ee9 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt @@ -23,4 +23,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents { fun openRewardsValidators() fun selectRewardValidator(rewardValue: String) + + fun onExploreClick() + + fun onShareClick() } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt index 7b76ca2694..61d9860dbb 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt @@ -21,6 +21,7 @@ import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.transaction.usecase.SendTransactionUseCase +import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase @@ -56,6 +57,7 @@ internal class StakingViewModel @Inject constructor( private val getUserWalletUseCase: GetUserWalletUseCase, private val initializeStakingProcessUseCase: InitializeStakingProcessUseCase, private val sendTransactionUseCase: SendTransactionUseCase, + private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents { @@ -97,18 +99,15 @@ internal class StakingViewModel @Inject constructor( } override fun onNextClick() { - handleOnNextConfirmClick() + handleOnNextConfirmationClick() stakingStateRouter.onNextClick() - if (value.currentStep == StakingStep.Confirm) { + if (isAssentState()) { initStaking() } } - private fun handleOnNextConfirmClick() { - if (value.currentStep == StakingStep.Confirm && - (value.confirmStakingState as? StakingStates.ConfirmStakingState.Data)?.innerState == - StakingStates.ConfirmStakingState.Data.InnerConfirmStakingState.CONFIRM - ) { + private fun handleOnNextConfirmationClick() { + if (isAssentState()) { viewModelScope.launch { stakingTransaction?.unsignedTransaction?.let { sendStakingTransaction(TransactionData.Compiled(value = it.hexToBytes())) @@ -120,7 +119,7 @@ internal class StakingViewModel @Inject constructor( private fun initStaking() { viewModelScope.launch { stateController.update( - SetConfirmStateLoadingTransformer( + SetConfirmationStateLoadingTransformer( yield = yield, ), ) @@ -144,7 +143,7 @@ internal class StakingViewModel @Inject constructor( val stakingGasEstimate = stakingTransaction.gasEstimate ?: error("Can't get fee info") stateController.update( - SetConfirmStateConfirmTransformer( + SetConfirmationStateAssentTransformer( appCurrencyProvider = Provider { appCurrency }, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, stakingGasEstimate = stakingGasEstimate, @@ -196,6 +195,20 @@ internal class StakingViewModel @Inject constructor( stakingStateRouter.onNextClick() } + override fun onExploreClick() { + val confirmationDataState = uiState.value.confirmationState as? StakingStates.ConfirmationState.Data + val transactionDoneState = confirmationDataState?.transactionDoneState as? TransactionDoneState.Content + val txUrl = transactionDoneState?.txUrl + + if (txUrl != null) { + innerRouter.openUrl(txUrl) + } + } + + override fun onShareClick() { + // TODO staking analytics event + } + fun setRouter(router: InnerStakingRouter, stateRouter: StakingStateRouter) { innerRouter = router this.stakingStateRouter = stateRouter @@ -254,7 +267,7 @@ internal class StakingViewModel @Inject constructor( } private suspend fun sendStakingTransaction(txData: TransactionData) { - stateController.update(SetConfirmStateInProgressTransformer()) + stateController.update(SetConfirmationStateInProgressTransformer()) sendTransactionUseCase( txData = txData, @@ -265,29 +278,35 @@ internal class StakingViewModel @Inject constructor( Timber.e(error.toString()) val gasEstimate = stakingTransaction?.gasEstimate ?: return@fold stateController.update( - SetConfirmStateConfirmTransformer( + SetConfirmationStateAssentTransformer( appCurrencyProvider = Provider { appCurrency }, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, stakingGasEstimate = gasEstimate, ), ) - // uiState = eventStateFactory.getSendTransactionErrorState( - // error = error, - // onConsume = { uiState = eventStateFactory.onConsumeEventState() }, - // ) - // analyticsEventHandler.send(SendAnalyticEvents.TransactionError(cryptoCurrency.symbol)) }, - ifRight = { + ifRight = { txHash -> val gasEstimate = stakingTransaction?.gasEstimate ?: return@fold + + val txUrl = getExplorerTransactionUrlUseCase( + txHash = txHash, + networkId = cryptoCurrencyStatus.currency.network.id, + ).getOrElse { "" } stateController.update( - SetConfirmStateConfirmTransformer( + SetConfirmationStateCompletedTransformer( appCurrencyProvider = Provider { appCurrency }, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, stakingGasEstimate = gasEstimate, + txUrl = txUrl, ), ) - // sendScreenAnalyticSender.sendTransaction() }, ) } + + private fun isAssentState(): Boolean { + return value.currentStep == StakingStep.Confirmation && + (value.confirmationState as? StakingStates.ConfirmationState.Data)?.innerState == + InnerConfirmationStakingState.ASSENT + } } \ No newline at end of file