diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 982967b3ea..a267125f20 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -49,6 +49,7 @@ import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.send.api.navigation.SendRouter +import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter @@ -158,6 +159,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var emailSender: EmailSender + @Inject + lateinit var stakingRouter: StakingRouter + internal val viewModel: MainViewModel by viewModels() private lateinit var appThemeModeFlow: SharedFlow @@ -242,6 +246,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac sendRouter = sendRouter, qrScanningRouter = qrScanningRouter, emailSender = emailSender, + stakingRouter = stakingRouter, ), ) } diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 4b0a740760..70631857fc 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -167,5 +167,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.SaveWallet -> SaveWalletBottomSheetFragment() AppScreen.AppCurrencySelector -> AppCurrencySelectorFragment() AppScreen.ModalNotification -> ModalNotificationBottomSheetFragment() + AppScreen.Staking -> store.inject(getDependency = DaggerGraphState::stakingRouter).getEntryFragment() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt index f854ba0dae..3b479b590c 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt @@ -6,6 +6,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.send.api.navigation.SendRouter +import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter @@ -25,5 +26,6 @@ sealed interface DaggerGraphAction : Action { val sendRouter: SendRouter, val qrScanningRouter: QrScanningRouter, val emailSender: EmailSender, + val stakingRouter: StakingRouter, ) : DaggerGraphAction } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt index b25fdce12b..9f1f5fddca 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt @@ -23,6 +23,7 @@ object DaggerGraphReducer { sendRouter = action.sendRouter, qrScanningRouter = action.qrScanningRouter, emailSender = action.emailSender, + stakingRouter = action.stakingRouter, ) } } diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index a61bdcde57..3dc61535c0 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -30,6 +30,7 @@ import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggle import com.tangem.features.managetokens.navigation.ManageTokensUi import com.tangem.features.send.api.featuretoggles.SendFeatureToggles import com.tangem.features.send.api.navigation.SendRouter +import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter @@ -79,4 +80,5 @@ data class DaggerGraphState( val assetLoader: AssetLoader? = null, val detailsFeatureToggles: DetailsFeatureToggles? = null, val detailsEntryPoint: DetailsEntryPoint? = null, + val stakingRouter: StakingRouter? = null, ) : StateType \ No newline at end of file diff --git a/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt b/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt index a0a6d64f25..40d6612fed 100644 --- a/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt +++ b/core/navigation/src/main/java/com/tangem/core/navigation/NavigationState.kt @@ -35,4 +35,5 @@ enum class AppScreen(val isDialogFragment: Boolean = false) { SaveWallet(isDialogFragment = true), AppCurrencySelector, ModalNotification(isDialogFragment = true), + Staking, } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/ScenarioUnavailabilityReason.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/ScenarioUnavailabilityReason.kt index ead2d06c56..340ca7d60d 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/ScenarioUnavailabilityReason.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/ScenarioUnavailabilityReason.kt @@ -27,6 +27,6 @@ sealed class ScenarioUnavailabilityReason { data object UnassociatedAsset : ScenarioUnavailabilityReason() enum class WithdrawalScenario { - SELL, SEND + SELL, SEND // TODO staking create&process STAKING } } \ No newline at end of file diff --git a/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/navigation/StakingRouter.kt b/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/navigation/StakingRouter.kt index d2b216513e..1749258dfd 100644 --- a/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/navigation/StakingRouter.kt +++ b/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/navigation/StakingRouter.kt @@ -5,4 +5,9 @@ import androidx.fragment.app.Fragment interface StakingRouter { fun getEntryFragment(): Fragment + + companion object { + const val CRYPTO_CURRENCY_KEY = "CRYPTO_CURRENCY_KEY" + const val USER_WALLET_ID_KEY = "USER_WALLET_ID_KEY" + } } \ No newline at end of file diff --git a/features/staking/impl/build.gradle.kts b/features/staking/impl/build.gradle.kts index ac2ce74301..5640ea3503 100644 --- a/features/staking/impl/build.gradle.kts +++ b/features/staking/impl/build.gradle.kts @@ -47,6 +47,15 @@ dependencies { implementation(projects.core.analytics) implementation(projects.core.analytics.models) + + /** Domain */ + implementation(projects.domain.tokens) + implementation(projects.domain.tokens.models) + implementation(projects.domain.wallets) + implementation(projects.domain.wallets.models) + implementation(projects.domain.balanceHiding) + implementation(projects.domain.balanceHiding.models) + /** Common */ implementation(projects.common) 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 83cd830e4d..351a4a7a28 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,8 +1,9 @@ package com.tangem.features.staking.impl.navigation import androidx.fragment.app.Fragment +import com.tangem.features.staking.impl.presentation.StakingFragment internal class DefaultStakingRouter : InnerStakingRouter { - override fun getEntryFragment(): Fragment = TODO() + override fun getEntryFragment(): Fragment = StakingFragment.create() } \ 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 7d7aa226d4..dd7187d902 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 @@ -2,4 +2,7 @@ package com.tangem.features.staking.impl.navigation import com.tangem.features.staking.api.navigation.StakingRouter -interface InnerStakingRouter : StakingRouter \ No newline at end of file +interface InnerStakingRouter : StakingRouter { + + // TODO staking +} \ 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 new file mode 100644 index 0000000000..fab926ce46 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/StakingFragment.kt @@ -0,0 +1,73 @@ +package com.tangem.features.staking.impl.presentation + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.ui.UiDependencies +import com.tangem.core.ui.components.SystemBarsEffect +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.screen.ComposeFragment +import com.tangem.features.staking.api.navigation.StakingRouter +import com.tangem.features.staking.impl.navigation.InnerStakingRouter +import com.tangem.features.staking.impl.presentation.state.StakingStateRouter +import com.tangem.features.staking.impl.presentation.viewmodel.StakingViewModel +import dagger.hilt.android.AndroidEntryPoint +import java.lang.ref.WeakReference +import javax.inject.Inject + +/** + * Staking fragment + */ +@AndroidEntryPoint +internal class StakingFragment : ComposeFragment() { + + @Inject + override lateinit var uiDependencies: UiDependencies + + @Inject + lateinit var router: StakingRouter + + @Inject + lateinit var analyticsEventsHandler: AnalyticsEventHandler + + private val viewModel by viewModels() + private val innerStakingRouter: InnerStakingRouter + get() = requireNotNull(router as? InnerStakingRouter) { + "innerStakingRouter should be instance of InnerStakingRouter" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + lifecycle.addObserver(viewModel) + + viewModel.setRouter( + innerStakingRouter, + StakingStateRouter( + fragmentManager = WeakReference(parentFragmentManager), + ), + ) + } + + @Composable + override fun ScreenContent(modifier: Modifier) { + val systemBarsColor = TangemTheme.colors.background.tertiary + SystemBarsEffect { + setSystemBarsColor(systemBarsColor) + } + val currentState = viewModel.stakingStateRouter.currentState.collectAsStateWithLifecycle() + // StakingScreen(viewModel.uiState, currentState.value) + } + + override fun onDestroy() { + lifecycle.removeObserver(viewModel) + super.onDestroy() + } + + companion object { + /** Create staking fragment instance */ + fun create(): StakingFragment = StakingFragment() + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingAlertState.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingAlertState.kt new file mode 100644 index 0000000000..c133fe00ca --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingAlertState.kt @@ -0,0 +1,24 @@ +package com.tangem.features.staking.impl.presentation.state + +import androidx.compose.runtime.Immutable +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.features.staking.impl.R + +@Immutable +internal sealed class StakingAlertState { + + abstract val title: TextReference? + abstract val message: TextReference + open val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok) + open val onConfirmClick: (() -> Unit)? = null + + data class GenericError( + override val title: TextReference? = TODO(), + override val onConfirmClick: () -> Unit, + ) : StakingAlertState() { + override val message: TextReference = resourceReference(R.string.common_unknown_error) + override val confirmButtonText: TextReference = + resourceReference(id = R.string.common_support) + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingEvent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingEvent.kt new file mode 100644 index 0000000000..dbc800ea01 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingEvent.kt @@ -0,0 +1,12 @@ +package com.tangem.features.staking.impl.presentation.state + +import androidx.compose.runtime.Immutable +import com.tangem.core.ui.extensions.TextReference + +@Immutable +internal sealed class StakingEvent { + + data class ShowSnackBar(val text: TextReference) : StakingEvent() + + data class ShowAlert(val alert: StakingAlertState) : StakingEvent() +} \ 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 new file mode 100644 index 0000000000..1d0095389b --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt @@ -0,0 +1,47 @@ +package com.tangem.features.staking.impl.presentation.state + +import com.tangem.core.ui.event.consumedEvent +import com.tangem.features.staking.impl.presentation.state.transformers.StakingScreenStateTransformer +import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +internal class StakingStateController @Inject constructor() { + + val value: StakingUiState get() = uiState.value + + private val mutableUiState: MutableStateFlow = MutableStateFlow(value = getInitialState()) + + val uiState: StateFlow get() = mutableUiState.asStateFlow() + + fun update(function: (StakingUiState) -> StakingUiState) { + mutableUiState.update(function = function) + } + + fun update(transformer: StakingScreenStateTransformer) { + mutableUiState.update(function = transformer::transform) + } + + fun clear() { + mutableUiState.update { getInitialState() } + } + + private fun getInitialState(): StakingUiState { + return StakingUiState( + clickIntents = object : StakingClickIntents {}, + cryptoCurrencyName = "", + currentScreen = StakingUiStateType.InitialInfo, + initialInfoState = StakingStates.InitialInfoState.Empty(), + amountState = StakingStates.AmountState.Empty(), + validatorState = StakingStates.ValidatorState.Empty(), + confirmStakingState = StakingStates.ConfirmStakingState.Empty(), + isBalanceHidden = false, + event = consumedEvent(), + ) + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..8e7182f088 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt @@ -0,0 +1,72 @@ +package com.tangem.features.staking.impl.presentation.state + +import androidx.fragment.app.FragmentManager +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import java.lang.ref.WeakReference + +internal class StakingStateRouter( + private val fragmentManager: WeakReference, +) { + private var mutableCurrentState: MutableStateFlow = MutableStateFlow(getInitState()) + + val currentState: StateFlow + get() = mutableCurrentState.asStateFlow() + + fun clear() { + mutableCurrentState.update { getInitState() } + } + + fun popBackStack() { + fragmentManager.get()?.popBackStack() + } + + fun onBackClick(isSuccess: Boolean = false) { + val type = currentState.value + when { + isSuccess -> popBackStack() + else -> when (type) { + StakingUiStateType.Amount -> showInitial() + StakingUiStateType.ValidatorAndFee -> showAmount() + else -> popBackStack() + } + } + } + + fun onNextClick() { + when (currentState.value) { + StakingUiStateType.InitialInfo -> showAmount() + StakingUiStateType.Amount, + StakingUiStateType.ValidatorAndFee, + -> showConfirm() + StakingUiStateType.Confirm -> onBackClick() + } + } + + fun onPrevClick() { + when (currentState.value) { + StakingUiStateType.Amount -> showInitial() + else -> popBackStack() + } + } + + private fun showInitial() { + mutableCurrentState.update { StakingUiStateType.InitialInfo } + } + + fun showAmount() { + mutableCurrentState.update { StakingUiStateType.Amount } + } + + fun showValidator() { + mutableCurrentState.update { StakingUiStateType.ValidatorAndFee } + } + + fun showConfirm() { + mutableCurrentState.update { StakingUiStateType.Confirm } + } + + private fun getInitState() = StakingUiStateType.InitialInfo +} \ 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 new file mode 100644 index 0000000000..8355cab544 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingUiState.kt @@ -0,0 +1,101 @@ +package com.tangem.features.staking.impl.presentation.state + +import androidx.compose.runtime.Immutable +import com.tangem.core.ui.event.StateEvent +import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents + +/** + * Ui states of the staking screen + */ +@Immutable +internal data class StakingUiState( + val clickIntents: StakingClickIntents, + val cryptoCurrencyName: String, + val currentScreen: StakingUiStateType, + val initialInfoState: StakingStates.InitialInfoState, + val amountState: StakingStates.AmountState, + val validatorState: StakingStates.ValidatorState, + val confirmStakingState: StakingStates.ConfirmStakingState, + val isBalanceHidden: Boolean, + val event: StateEvent, +) { + + fun copyWrapped( + initialInfoState: StakingStates.InitialInfoState = this.initialInfoState, + amountState: StakingStates.AmountState = this.amountState, + validatorState: StakingStates.ValidatorState = this.validatorState, + confirmStakingState: StakingStates.ConfirmStakingState = this.confirmStakingState, + ): StakingUiState = copy( + initialInfoState = initialInfoState, + amountState = amountState, + validatorState = validatorState, + confirmStakingState = confirmStakingState, + ) +} + +internal sealed class StakingStates { + + abstract val isPrimaryButtonEnabled: Boolean + + /** Initial info state */ + sealed class InitialInfoState : StakingStates() { + data class Data( + override val isPrimaryButtonEnabled: Boolean, + ) : InitialInfoState() + + data class Empty( + override val isPrimaryButtonEnabled: Boolean = false, + ) : InitialInfoState() + } + + /** Amount state */ + sealed class AmountState : StakingStates() { + data class Data( + override val isPrimaryButtonEnabled: Boolean, + ) : AmountState() + + data class Empty( + override val isPrimaryButtonEnabled: Boolean = false, + ) : AmountState() + } + + /** Validator state */ + sealed class ValidatorState : StakingStates() { + data class Data( + override val isPrimaryButtonEnabled: Boolean, + ) : ValidatorState() + + data class Empty( + override val isPrimaryButtonEnabled: Boolean = false, + ) : ValidatorState() + } + + /** Fee state */ + sealed class FeeState : StakingStates() { + data class Data( + override val isPrimaryButtonEnabled: Boolean, + ) : FeeState() + + data class Empty( + override val isPrimaryButtonEnabled: Boolean = false, + ) : FeeState() + } + + /** Confirm state */ + sealed class ConfirmStakingState : StakingStates() { + data class Data( + override val isPrimaryButtonEnabled: Boolean, + ) : ConfirmStakingState() + + data class Empty( + override val isPrimaryButtonEnabled: Boolean = false, + ) : ConfirmStakingState() + } +} + +enum class StakingUiStateType { + InitialInfo, + Amount, + ValidatorAndFee, + Confirm, +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/HideBalanceStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/HideBalanceStateTransformer.kt new file mode 100644 index 0000000000..90afd05bb9 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/HideBalanceStateTransformer.kt @@ -0,0 +1,12 @@ +package com.tangem.features.staking.impl.presentation.state.transformers + +import com.tangem.features.staking.impl.presentation.state.StakingUiState + +internal class HideBalanceStateTransformer( + private val isBalanceHidden: Boolean, +) : StakingScreenStateTransformer { + + override fun transform(prevState: StakingUiState): StakingUiState { + return prevState.copy(isBalanceHidden = isBalanceHidden) + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/StakingScreenStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/StakingScreenStateTransformer.kt new file mode 100644 index 0000000000..05d13135f0 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/StakingScreenStateTransformer.kt @@ -0,0 +1,8 @@ +package com.tangem.features.staking.impl.presentation.state.transformers + +import com.tangem.features.staking.impl.presentation.state.StakingUiState + +internal interface StakingScreenStateTransformer { + + fun transform(prevState: StakingUiState): StakingUiState +} \ No newline at end of file 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 new file mode 100644 index 0000000000..1aec6214cd --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt @@ -0,0 +1,5 @@ +package com.tangem.features.staking.impl.presentation.viewmodel + +internal interface StakingClickIntents { + // TODO staking +} \ 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 new file mode 100644 index 0000000000..91cb3a2423 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt @@ -0,0 +1,84 @@ +package com.tangem.features.staking.impl.presentation.viewmodel + +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase +import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.features.staking.api.navigation.StakingRouter +import com.tangem.features.staking.impl.navigation.InnerStakingRouter +import com.tangem.features.staking.impl.presentation.state.StakingStateController +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.features.staking.impl.presentation.state.StakingStateRouter +import com.tangem.features.staking.impl.presentation.state.transformers.HideBalanceStateTransformer +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject +import kotlin.properties.Delegates + +@HiltViewModel +internal class StakingViewModel @Inject constructor( + private val stateController: StakingStateController, + private val dispatchers: CoroutineDispatcherProvider, + private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, + private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase, + savedStateHandle: SavedStateHandle, +) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents { + + val uiState: StateFlow = stateController.uiState + val value: StakingUiState get() = uiState.value + + var stakingStateRouter: StakingStateRouter by Delegates.notNull() + private set + + private val cryptoCurrency: CryptoCurrency = savedStateHandle[StakingRouter.CRYPTO_CURRENCY_KEY] + ?: error("This screen can't open without `CryptoCurrency`") + + private val userWalletId: UserWalletId = savedStateHandle.get(StakingRouter.USER_WALLET_ID_KEY) + ?.let { stringValue -> UserWalletId(stringValue) } + ?: error("This screen can't open without `UserWalletId`") + + private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() + + private var innerRouter: InnerStakingRouter by Delegates.notNull() + + init { + subscribeOnBalanceHiding() + subscribeOnCurrencyStatusUpdates() + } + + fun setRouter(router: InnerStakingRouter, stakingStateRouter: StakingStateRouter) { + innerRouter = router + this.stakingStateRouter = stakingStateRouter + } + + private fun subscribeOnCurrencyStatusUpdates() { + viewModelScope.launch { + getCryptoCurrencyStatusSyncUseCase(userWalletId, cryptoCurrency.id).fold( + ifRight = { + cryptoCurrencyStatus = it + }, + ifLeft = { + // TODO staking error + }, + ) + } + } + + private fun subscribeOnBalanceHiding() { + getBalanceHidingSettingsUseCase() + .conflate() + .distinctUntilChanged() + .onEach { + stateController.update(transformer = HideBalanceStateTransformer(it.isBalanceHidden)) + } + .flowOn(dispatchers.main) + .launchIn(viewModelScope) + } +} \ No newline at end of file