diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 0fcd5636c2..0e5b92b3ea 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -65,7 +65,6 @@ import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.features.send.api.navigation.SendRouter -import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter import com.tangem.google.GoogleServicesHelper @@ -178,9 +177,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac @Inject lateinit var emailSender: EmailSender - @Inject - lateinit var stakingRouter: StakingRouter - @Inject @RootAppComponentContext internal lateinit var rootComponentContext: AppComponentContext diff --git a/app/src/main/java/com/tangem/tap/di/domain/TxHistoryDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TxHistoryDomainModule.kt index 7f0c9abe88..98eb94e42e 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TxHistoryDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TxHistoryDomainModule.kt @@ -1,6 +1,5 @@ package com.tangem.tap.di.domain -import com.tangem.domain.tokens.* import com.tangem.domain.txhistory.repository.TxHistoryRepository import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase @@ -9,27 +8,23 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.ViewModelComponent -import dagger.hilt.android.scopes.ViewModelScoped +import dagger.hilt.components.SingletonComponent @Module -@InstallIn(ViewModelComponent::class) +@InstallIn(SingletonComponent::class) internal object TxHistoryDomainModule { @Provides - @ViewModelScoped fun provideGetTxHistoryItemsCountUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsCountUseCase { return GetTxHistoryItemsCountUseCase(repository = txHistoryRepository) } @Provides - @ViewModelScoped fun provideGetTxHistoryItemsUseCase(txHistoryRepository: TxHistoryRepository): GetTxHistoryItemsUseCase { return GetTxHistoryItemsUseCase(repository = txHistoryRepository) } @Provides - @ViewModelScoped fun providesGetExplorerTransactionUrlUseCase( txHistoryRepository: TxHistoryRepository, ): GetExplorerTransactionUrlUseCase { @@ -37,7 +32,6 @@ internal object TxHistoryDomainModule { } @Provides - @ViewModelScoped fun providesGetFixedTxHistoryItemsUseCase(txHistoryRepository: TxHistoryRepository): GetFixedTxHistoryItemsUseCase { return GetFixedTxHistoryItemsUseCase(repository = txHistoryRepository) } 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 2333f95cf5..3c36d9833b 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 @@ -1,7 +1,6 @@ package com.tangem.tap.proxy.redux import com.tangem.blockchainsdk.BlockchainSDKFactory -import com.tangem.data.card.TransactionSignerFactory import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.common.routing.AppRouter import com.tangem.core.decompose.ui.UiMessageSender @@ -9,6 +8,7 @@ import com.tangem.core.navigation.settings.SettingsManager import com.tangem.core.navigation.share.ShareManager import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.clipboard.ClipboardManager +import com.tangem.data.card.TransactionSignerFactory import com.tangem.datasource.connection.NetworkConnectionManager import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage import com.tangem.datasource.local.config.issuers.IssuersConfigStorage @@ -34,7 +34,6 @@ import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.features.onramp.OnrampFeatureToggles import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter -import com.tangem.features.staking.api.navigation.StakingRouter import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor @@ -65,7 +64,6 @@ data class DaggerGraphState( val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase? = null, val getCardInfoUseCase: GetCardInfoUseCase? = null, val issuersConfigStorage: IssuersConfigStorage? = null, - val stakingRouter: StakingRouter? = null, val urlOpener: UrlOpener? = null, val shareManager: ShareManager? = null, val appRouter: AppRouter? = null, diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 47c916c3b6..70338653b9 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -16,7 +16,7 @@ import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent import com.tangem.features.onramp.component.* import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter import com.tangem.features.send.api.navigation.SendRouter -import com.tangem.features.staking.api.navigation.StakingRouter +import com.tangem.features.staking.api.StakingComponent import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.features.wallet.navigation.WalletRouter @@ -58,11 +58,11 @@ internal class ChildFactory @Inject constructor( private val onboardingEntryComponentFactory: OnboardingEntryComponent.Factory, private val welcomeComponentFactory: WelcomeComponent.Factory, private val storiesComponentFactory: StoriesComponent.Factory, + private val stakingComponentFactory: StakingComponent.Factory, private val sendRouter: SendRouter, private val tokenDetailsRouter: TokenDetailsRouter, private val walletRouter: WalletRouter, private val qrScanningRouter: QrScanningRouter, - private val stakingRouter: StakingRouter, private val testerRouter: TesterRouter, private val pushNotificationRouter: PushNotificationsRouter, private val routingFeatureToggles: RoutingFeatureToggles, @@ -211,6 +211,17 @@ internal class ChildFactory @Inject constructor( componentFactory = storiesComponentFactory, ) } + is AppRoute.Staking -> { + createComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = StakingComponent.Params( + userWalletId = route.userWalletId, + cryptoCurrencyId = route.cryptoCurrencyId, + yield = route.yield, + ), + componentFactory = stakingComponentFactory, + ) + } is AppRoute.AccessCodeRecovery, is AppRoute.AppCurrencySelector, is AppRoute.SaveWallet, @@ -230,7 +241,6 @@ internal class ChildFactory @Inject constructor( is AppRoute.Wallet, is AppRoute.WalletConnectSessions, is AppRoute.CurrencyDetails, - is AppRoute.Staking, is AppRoute.PushNotification, -> error("Unsupported route: $route") } @@ -337,7 +347,15 @@ internal class ChildFactory @Inject constructor( Child.LegacyIntent(testerRouter.getEntryIntent()) } is AppRoute.Staking -> { - route.asFragmentChild(Provider { stakingRouter.getEntryFragment() }) + route.asComponentChild( + contextProvider = contextProvider(route, contextFactory), + params = StakingComponent.Params( + userWalletId = route.userWalletId, + cryptoCurrencyId = route.cryptoCurrencyId, + yield = route.yield, + ), + componentFactory = stakingComponentFactory, + ) } is AppRoute.PushNotification -> { route.asFragmentChild(Provider { pushNotificationRouter.entryFragment() }) diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index 28d839feba..f2c6c70148 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -257,17 +257,7 @@ sealed class AppRoute(val path: String) : Route { val userWalletId: UserWalletId, val cryptoCurrencyId: CryptoCurrency.ID, val yield: Yield, - ) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrencyId.value}/${yield.id}"), - RouteBundleParams { - - override fun getBundle(): Bundle = bundle(serializer()) - - companion object { - const val USER_WALLET_ID_KEY = "userWalletId" - const val CRYPTO_CURRENCY_ID_KEY = "cryptoCurrencyId" - const val YIELD_KEY = "yield" - } - } + ) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrencyId.value}/${yield.id}") @Serializable data object PushNotification : AppRoute(path = "/push_notification") diff --git a/features/staking/api/build.gradle.kts b/features/staking/api/build.gradle.kts index a14e2d42b0..b2266699a2 100644 --- a/features/staking/api/build.gradle.kts +++ b/features/staking/api/build.gradle.kts @@ -10,6 +10,14 @@ android { } dependencies { + /** Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + + /** Domain models */ + implementation(projects.domain.staking.models) + implementation(projects.domain.tokens.models) + implementation(projects.domain.wallets.models) /** AndroidX */ implementation(deps.androidx.fragment.ktx) diff --git a/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt b/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt new file mode 100644 index 0000000000..207a7bdc94 --- /dev/null +++ b/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/StakingComponent.kt @@ -0,0 +1,18 @@ +package com.tangem.features.staking.api + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.staking.model.stakekit.Yield +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId + +interface StakingComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + val cryptoCurrencyId: CryptoCurrency.ID, + val yield: Yield, + ) + + interface Factory : ComponentFactory +} \ 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 deleted file mode 100644 index d2b216513e..0000000000 --- a/features/staking/api/src/main/kotlin/com/tangem/features/staking/api/navigation/StakingRouter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.features.staking.api.navigation - -import androidx.fragment.app.Fragment - -interface StakingRouter { - - fun getEntryFragment(): Fragment -} \ No newline at end of file diff --git a/features/staking/impl/build.gradle.kts b/features/staking/impl/build.gradle.kts index 6c77d65471..be3dbdd1e2 100644 --- a/features/staking/impl/build.gradle.kts +++ b/features/staking/impl/build.gradle.kts @@ -46,6 +46,7 @@ dependencies { implementation(projects.core.navigation) implementation(projects.core.analytics) implementation(projects.core.analytics.models) + implementation(projects.core.decompose) /** Domain */ diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/DefaultStakingComponent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/DefaultStakingComponent.kt new file mode 100644 index 0000000000..3f40fea39d --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/DefaultStakingComponent.kt @@ -0,0 +1,33 @@ +package com.tangem.features.staking.impl + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.features.staking.api.StakingComponent +import com.tangem.features.staking.impl.presentation.model.StakingModel +import com.tangem.features.staking.impl.presentation.ui.StakingScreen +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +internal class DefaultStakingComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted params: StakingComponent.Params, +) : StakingComponent, AppComponentContext by appComponentContext { + + private val model: StakingModel = getOrCreateModel(params) + + @Composable + override fun Content(modifier: Modifier) { + val currentState by model.uiState.collectAsStateWithLifecycle() + StakingScreen(currentState) + } + + @AssistedFactory + interface Factory : StakingComponent.Factory { + override fun create(context: AppComponentContext, params: StakingComponent.Params): DefaultStakingComponent + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt new file mode 100644 index 0000000000..c2fc6404b9 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingModule.kt @@ -0,0 +1,38 @@ +package com.tangem.features.staking.impl.di + +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.di.DecomposeComponent +import com.tangem.core.decompose.model.Model +import com.tangem.features.staking.api.StakingComponent +import com.tangem.features.staking.impl.DefaultStakingComponent +import com.tangem.features.staking.impl.navigation.DefaultStakingRouter +import com.tangem.features.staking.impl.navigation.InnerStakingRouter +import com.tangem.features.staking.impl.presentation.model.StakingModel +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +@InstallIn(SingletonComponent::class) +internal interface StakingModule { + + @Binds + fun bindComponentFactory(factory: DefaultStakingComponent.Factory): StakingComponent.Factory + + @Binds + @IntoMap + @ClassKey(StakingModel::class) + fun bindModel(model: StakingModel): Model +} + +@Module +@InstallIn(DecomposeComponent::class) +internal interface StakingComponentModule { + + @Binds + @ComponentScoped + fun bindRouter(impl: DefaultStakingRouter): InnerStakingRouter +} \ No newline at end of file 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 deleted file mode 100644 index 1e01cf0b3d..0000000000 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/di/StakingRouterModule.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.tangem.features.staking.impl.di - -import com.tangem.common.routing.AppRouter -import com.tangem.core.navigation.url.UrlOpener -import com.tangem.features.staking.api.navigation.StakingRouter -import com.tangem.features.staking.impl.navigation.DefaultStakingRouter -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent -import dagger.hilt.android.scopes.ActivityScoped - -/** - * DI module provides implementation of [StakingRouter] - */ -@Module -@InstallIn(ActivityComponent::class) -internal object StakingRouterModule { - - @Provides - @ActivityScoped - fun provideStakingRouter(urlOpener: UrlOpener, router: AppRouter): StakingRouter { - return DefaultStakingRouter( - urlOpener = urlOpener, - router = router, - ) - } -} \ 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 6acad0658b..9a600a0a93 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,18 +1,18 @@ package com.tangem.features.staking.impl.navigation -import androidx.fragment.app.Fragment import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter +import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.navigation.url.UrlOpener import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.features.staking.impl.presentation.StakingFragment +import javax.inject.Inject -internal class DefaultStakingRouter( +@ComponentScoped +internal class DefaultStakingRouter @Inject constructor( private val urlOpener: UrlOpener, private val router: AppRouter, ) : InnerStakingRouter { - override fun getEntryFragment(): Fragment = StakingFragment.create() override fun openUrl(url: String) { urlOpener.openUrl(url) 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 e1fec4bab1..f7d5ab5fa6 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,9 +2,8 @@ package com.tangem.features.staking.impl.navigation import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.features.staking.api.navigation.StakingRouter -interface InnerStakingRouter : StakingRouter { +internal interface InnerStakingRouter { fun openUrl(url: String) 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 deleted file mode 100644 index 1740d65084..0000000000 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/StakingFragment.kt +++ /dev/null @@ -1,77 +0,0 @@ -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.common.routing.AppRouter -import com.tangem.core.analytics.api.AnalyticsEventHandler -import com.tangem.core.ui.UiDependencies -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.StakingStateController -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 javax.inject.Inject - -/** - * Staking fragment - */ -@AndroidEntryPoint -internal class StakingFragment : ComposeFragment() { - - @Inject - override lateinit var uiDependencies: UiDependencies - - @Inject - lateinit var stakingRouter: StakingRouter - - @Inject - lateinit var appRouter: AppRouter - - @Inject - lateinit var stateController: StakingStateController - - @Inject - lateinit var analyticsEventsHandler: AnalyticsEventHandler - - private val viewModel by viewModels() - private val innerStakingRouter: InnerStakingRouter - get() = requireNotNull(stakingRouter as? InnerStakingRouter) { - "innerStakingRouter should be instance of InnerStakingRouter" - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - lifecycle.addObserver(viewModel) - - viewModel.setRouter( - innerStakingRouter, - StakingStateRouter( - appRouter = appRouter, - stateController = stateController, - analyticsEventsHandler = analyticsEventsHandler, - ), - ) - } - - @Composable - override fun ScreenContent(modifier: Modifier) { - val currentState = viewModel.uiState.collectAsStateWithLifecycle() - StakingScreen(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/viewmodel/StakingClickIntents.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingClickIntents.kt similarity index 96% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingClickIntents.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingClickIntents.kt index 1b4d3eeee4..19f4af3993 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/model/StakingClickIntents.kt @@ -1,4 +1,4 @@ -package com.tangem.features.staking.impl.presentation.viewmodel +package com.tangem.features.staking.impl.presentation.model import com.tangem.common.ui.amountScreen.AmountScreenClickIntents import com.tangem.common.ui.bottomsheet.permission.state.ApproveType 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/model/StakingModel.kt similarity index 95% rename from features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt rename to features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index 1dc4ce0e48..bb2c07e2c4 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/model/StakingModel.kt @@ -1,14 +1,9 @@ -package com.tangem.features.staking.impl.presentation.viewmodel +package com.tangem.features.staking.impl.presentation.model -import android.os.Bundle -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import androidx.compose.runtime.Stable import arrow.core.getOrElse import com.tangem.blockchain.common.transaction.TransactionFee -import com.tangem.common.routing.AppRoute -import com.tangem.common.routing.bundle.unbundle +import com.tangem.common.routing.AppRouter import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary @@ -17,6 +12,9 @@ import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionBottomS import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.ParamsInterceptorHolder +import com.tangem.core.decompose.di.ComponentScoped +import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.share.ShareManager import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.haptic.VibratorHapticManager @@ -52,6 +50,7 @@ import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.features.staking.api.StakingComponent import com.tangem.features.staking.impl.analytics.StakingParamsInterceptor import com.tangem.features.staking.impl.analytics.utils.StakingAnalyticSender import com.tangem.features.staking.impl.navigation.InnerStakingRouter @@ -77,7 +76,6 @@ import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import com.tangem.utils.extensions.isSingleItem import com.tangem.utils.extensions.orZero -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope @@ -89,11 +87,13 @@ import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject import kotlin.properties.Delegates -@Suppress("LargeClass", "LongParameterList", "TooManyFunctions") -@HiltViewModel -internal class StakingViewModel @Inject constructor( +@Suppress("LargeClass", "TooManyFunctions", "LongParameterList") +@Stable +@ComponentScoped +internal class StakingModel @Inject constructor( + paramsContainer: ParamsContainer, private val stateController: StakingStateController, - private val dispatchers: CoroutineDispatcherProvider, + override val dispatchers: CoroutineDispatcherProvider, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase, private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase, @@ -122,33 +122,30 @@ internal class StakingViewModel @Inject constructor( private val paramsInterceptorHolder: ParamsInterceptorHolder, private val shareManager: ShareManager, @DelayedWork private val coroutineScope: CoroutineScope, - savedStateHandle: SavedStateHandle, -) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents { + private val innerRouter: InnerStakingRouter, + private val appRouter: AppRouter, +) : Model(), StakingClickIntents { val uiState: StateFlow = stateController.uiState val value: StakingUiState get() = uiState.value - private var stakingStateRouter: StakingStateRouter by Delegates.notNull() + private val params = paramsContainer.require() - private val cryptoCurrencyId: CryptoCurrency.ID = - savedStateHandle.get(AppRoute.Staking.CRYPTO_CURRENCY_ID_KEY) - ?.unbundle(CryptoCurrency.ID.serializer()) - ?: error("This screen can't be opened without `CryptoCurrency.ID`") + private var stakingStateRouter: StakingStateRouter = StakingStateRouter( + appRouter = appRouter, + stateController = stateController, + analyticsEventsHandler = analyticsEventHandler, + ) - private val userWalletId: UserWalletId = savedStateHandle.get(AppRoute.Staking.USER_WALLET_ID_KEY) - ?.unbundle(UserWalletId.serializer()) - ?: error("This screen can't be opened without `UserWalletId`") - - private val yield: Yield = savedStateHandle.get(AppRoute.Staking.YIELD_KEY) - ?.unbundle(Yield.serializer()) - ?: error("This screen can't be opened without `Yield`") + private val cryptoCurrencyId: CryptoCurrency.ID = params.cryptoCurrencyId + private val userWalletId: UserWalletId = params.userWalletId + private val yield: Yield = params.yield private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() private var processingActions: List = emptyList() private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null private var minimumTransactionAmount: EnterAmountBoundary? = null - private var innerRouter: InnerStakingRouter by Delegates.notNull() private var userWallet: UserWallet by Delegates.notNull() private var appCurrency: AppCurrency by Delegates.notNull() @@ -218,8 +215,8 @@ internal class StakingViewModel @Inject constructor( subscribeOnCurrencyStatusUpdates() } - override fun onCleared() { - super.onCleared() + override fun onDestroy() { + super.onDestroy() paramsInterceptorHolder.removeParamsInterceptor(StakingParamsInterceptor.ID) approvalJobHolder.cancel() feeJobHolder.cancel() @@ -266,7 +263,7 @@ internal class StakingViewModel @Inject constructor( cryptoCurrency = cryptoCurrencyStatus.currency, ), ) - viewModelScope.launch { + modelScope.launch { feeLoader.getFee( onStakingFee = { gasEstimate -> stateController.update( @@ -303,7 +300,7 @@ internal class StakingViewModel @Inject constructor( override fun onActionClick() { if (isAssentState()) { - viewModelScope.launch { + modelScope.launch { stakingAnalyticSender.sendTransactionStakingClickedAnalytics(value) stateController.update(SetConfirmationStateInProgressTransformer()) transactionSender.constructAndSendTransactions( @@ -546,7 +543,7 @@ internal class StakingViewModel @Inject constructor( } override fun onApprovalClick() { - viewModelScope.launch { + modelScope.launch { stateController.update( SetApprovalBottomSheetInProgressTransformer { stateController.update(DismissBottomSheetStateTransformer) @@ -619,7 +616,7 @@ internal class StakingViewModel @Inject constructor( } private fun updateNotifications(feeError: GetFeeError? = null) { - viewModelScope.launch { + modelScope.launch { val confirmationState = value.confirmationState as? StakingStates.ConfirmationState.Data val feeState = confirmationState?.feeState as? FeeState.Content val amountState = value.amountState as? AmountState.Data @@ -733,7 +730,7 @@ internal class StakingViewModel @Inject constructor( private fun awaitForAllowance() { val approval = stakingApproval as? StakingApproval.Needed ?: return allowanceTaskScheduler.scheduleTask( - scope = viewModelScope, + scope = modelScope, task = PeriodicTask( delay = ALLOWANCE_UPDATE_DELAY, task = { @@ -783,7 +780,7 @@ internal class StakingViewModel @Inject constructor( } override fun onFailedTxEmailClick(errorMessage: String) { - viewModelScope.launch { + modelScope.launch { val network = cryptoCurrencyStatus.currency.network val cardInfo = getCardInfoUseCase(userWallet.scanResponse).getOrElse { error("CardInfo must be not null") } @@ -822,11 +819,6 @@ internal class StakingViewModel @Inject constructor( innerRouter.openTokenDetails(userWalletId, cryptoCurrency) } - fun setRouter(router: InnerStakingRouter, stateRouter: StakingStateRouter) { - innerRouter = router - this.stakingStateRouter = stateRouter - } - private suspend fun setupApprovalNeeded() { stakingApproval = isApproveNeededUseCase(cryptoCurrencyStatus.currency).fold( ifRight = { approval -> @@ -903,7 +895,7 @@ internal class StakingViewModel @Inject constructor( ) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun subscribeOnBalanceHiding() { @@ -914,7 +906,7 @@ internal class StakingViewModel @Inject constructor( stateController.update(transformer = HideBalanceStateTransformer(it.isBalanceHidden)) } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun subscribeOnSelectedAppCurrency() { @@ -925,7 +917,7 @@ internal class StakingViewModel @Inject constructor( appCurrency = maybeAppCurrency.getOrElse { AppCurrency.Default } } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun subscribeOnStepChanges() { @@ -951,7 +943,7 @@ internal class StakingViewModel @Inject constructor( } } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) .saveIn(stepChangesJobHolder) } @@ -971,13 +963,13 @@ internal class StakingViewModel @Inject constructor( } } .flowOn(dispatchers.main) - .launchIn(viewModelScope) + .launchIn(modelScope) } private fun updateInitialData() { stateController.updateAll( SetInitialDataStateTransformer( - clickIntents = this@StakingViewModel, + clickIntents = this@StakingModel, yield = yield, isAnyTokenStaked = isAnyTokenStaked, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, 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 604fbe7497..e4bc6089b6 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 @@ -14,7 +14,7 @@ import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType import com.tangem.features.staking.impl.presentation.state.events.StakingEvent -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import kotlinx.collections.immutable.ImmutableList import java.math.BigDecimal 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 514a94fc76..86f4d53799 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 @@ -6,7 +6,7 @@ import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.features.staking.impl.presentation.state.BalanceState import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import java.math.BigDecimal @Suppress("TooManyFunctions") diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt index 736d2d3fa2..d33a64975d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetAmountDataTransformer.kt @@ -12,7 +12,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.StakingUiState -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.utils.Provider import com.tangem.utils.transformer.Transformer 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 43d427fe49..873626c210 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 @@ -23,7 +23,7 @@ import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType 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.utils.getRewardScheduleText -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.lib.crypto.BlockchainUtils.isPolkadot import com.tangem.utils.Provider import com.tangem.utils.isNullOrZero diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt index 180306b99e..99b5c966bd 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt @@ -17,7 +17,7 @@ import com.tangem.core.ui.format.bigdecimal.percent import com.tangem.core.ui.res.TangemTheme import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.StakingStates -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.utils.extensions.orZero @Composable diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt index 765480203c..866458c643 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt @@ -29,7 +29,7 @@ import com.tangem.features.staking.impl.presentation.state.stub.StakingClickInte 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.presentation.model.StakingClickIntents @Suppress("LongParameterList") @Composable diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt index 63d2aacc70..a815b1b370 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt @@ -50,7 +50,7 @@ import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceStat import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.previewdata.InitialStakingStatePreview import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.utils.StringsSigns.DOT import com.tangem.utils.extensions.orZero 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 6afc60b7b3..a525deb6df 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 @@ -31,7 +31,7 @@ import com.tangem.features.staking.impl.R import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.previewdata.ValidatorStatePreviewData import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub -import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.utils.extensions.orZero /**