Updated on 2026-08-14
This commit is contained in:
parent
0b6257796a
commit
ed2eca7e8b
6 changed files with 133 additions and 85 deletions
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.tangem.tap.features.home
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import com.arkivanov.essenty.lifecycle.subscribe
|
||||||
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
|
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||||
|
import com.tangem.core.ui.utils.findActivity
|
||||||
|
import com.tangem.tap.common.redux.AppState
|
||||||
|
import com.tangem.tap.features.home.api.HomeComponent
|
||||||
|
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||||
|
import com.tangem.tap.features.home.redux.HomeAction
|
||||||
|
import com.tangem.tap.features.home.redux.HomeState
|
||||||
|
import com.tangem.tap.store
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import org.rekotlin.StoreSubscriber
|
||||||
|
|
||||||
|
@Suppress("UnusedPrivateMember")
|
||||||
|
internal class DefaultHomeComponent @AssistedInject constructor(
|
||||||
|
@Assisted appComponentContext: AppComponentContext,
|
||||||
|
@Assisted params: Unit,
|
||||||
|
) : HomeComponent, AppComponentContext by appComponentContext, StoreSubscriber<HomeState> {
|
||||||
|
|
||||||
|
private val model: HomeModel = getOrCreateModel()
|
||||||
|
|
||||||
|
private var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||||
|
|
||||||
|
init {
|
||||||
|
lifecycle.subscribe(
|
||||||
|
onCreate = {
|
||||||
|
store.dispatch(HomeAction.OnCreate)
|
||||||
|
},
|
||||||
|
onStart = {
|
||||||
|
store.subscribe(subscriber = this) { state ->
|
||||||
|
state
|
||||||
|
.skipRepeats { oldState, newState -> oldState.homeState == newState.homeState }
|
||||||
|
.select(AppState::homeState)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onStop = {
|
||||||
|
store.unsubscribe(this)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content(modifier: Modifier) {
|
||||||
|
val activity = LocalContext.current.findActivity()
|
||||||
|
BackHandler(onBack = activity::finish)
|
||||||
|
SystemBarsIconsDisposable(darkIcons = false)
|
||||||
|
StoriesScreen(
|
||||||
|
homeState = homeState,
|
||||||
|
onScanButtonClick = model::onScanClick,
|
||||||
|
onShopButtonClick = model::onShopClick,
|
||||||
|
onSearchTokensClick = model::onSearchClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newState(state: HomeState) {
|
||||||
|
homeState.value = state
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory : HomeComponent.Factory {
|
||||||
|
override fun create(context: AppComponentContext, params: Unit): DefaultHomeComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
package com.tangem.tap.features.home
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.activity.compose.BackHandler
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.MutableState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import com.tangem.core.ui.UiDependencies
|
|
||||||
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
|
||||||
import com.tangem.tap.common.redux.AppState
|
|
||||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
|
||||||
import com.tangem.tap.features.home.redux.HomeAction
|
|
||||||
import com.tangem.tap.features.home.redux.HomeState
|
|
||||||
import com.tangem.tap.store
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import org.rekotlin.StoreSubscriber
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
internal class HomeFragment : ComposeFragment(), StoreSubscriber<HomeState> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
override lateinit var uiDependencies: UiDependencies
|
|
||||||
|
|
||||||
private var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
|
||||||
|
|
||||||
private val viewModel by viewModels<HomeViewModel>()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
store.dispatch(HomeAction.OnCreate)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun ScreenContent(modifier: Modifier) {
|
|
||||||
BackHandler(onBack = requireActivity()::finish)
|
|
||||||
SystemBarsIconsDisposable(darkIcons = false)
|
|
||||||
ScreenContent()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
|
|
||||||
store.subscribe(subscriber = this) { state ->
|
|
||||||
state
|
|
||||||
.skipRepeats { oldState, newState -> oldState.homeState == newState.homeState }
|
|
||||||
.select(AppState::homeState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
store.unsubscribe(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newState(state: HomeState) {
|
|
||||||
if (activity == null || view == null) return
|
|
||||||
|
|
||||||
homeState.value = state
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("TopLevelComposableFunctions")
|
|
||||||
@Composable
|
|
||||||
private fun ScreenContent() {
|
|
||||||
StoriesScreen(
|
|
||||||
homeState = homeState,
|
|
||||||
onScanButtonClick = viewModel::onScanClick,
|
|
||||||
onShopButtonClick = viewModel::onShopClick,
|
|
||||||
onSearchTokensClick = viewModel::onSearchClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.tap.features.home
|
package com.tangem.tap.features.home
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.google.firebase.analytics.ktx.analytics
|
import com.google.firebase.analytics.ktx.analytics
|
||||||
import com.google.firebase.ktx.Firebase
|
import com.google.firebase.ktx.Firebase
|
||||||
import com.tangem.common.routing.AppRoute
|
import com.tangem.common.routing.AppRoute
|
||||||
|
|
@ -10,6 +9,8 @@ import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
|
import com.tangem.core.decompose.di.ComponentScoped
|
||||||
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.domain.card.ScanCardProcessor
|
import com.tangem.domain.card.ScanCardProcessor
|
||||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||||
|
|
@ -30,7 +31,7 @@ import com.tangem.tap.features.home.redux.HIDE_PROGRESS_DELAY
|
||||||
import com.tangem.tap.features.home.redux.HomeAction
|
import com.tangem.tap.features.home.redux.HomeAction
|
||||||
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
|
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -38,8 +39,10 @@ import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
@HiltViewModel
|
@Stable
|
||||||
internal class HomeViewModel @Inject constructor(
|
@ComponentScoped
|
||||||
|
internal class HomeModel @Inject constructor(
|
||||||
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val scanCardProcessor: ScanCardProcessor,
|
private val scanCardProcessor: ScanCardProcessor,
|
||||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||||
private val saveWalletUseCase: SaveWalletUseCase,
|
private val saveWalletUseCase: SaveWalletUseCase,
|
||||||
|
|
@ -47,7 +50,7 @@ internal class HomeViewModel @Inject constructor(
|
||||||
private val settingsRepository: SettingsRepository,
|
private val settingsRepository: SettingsRepository,
|
||||||
private val urlOpener: UrlOpener,
|
private val urlOpener: UrlOpener,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
) : ViewModel() {
|
) : Model() {
|
||||||
|
|
||||||
private val tangemErrorHandler = TangemTangemErrorsHandler(store)
|
private val tangemErrorHandler = TangemTangemErrorsHandler(store)
|
||||||
|
|
||||||
|
|
@ -73,7 +76,7 @@ internal class HomeViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scanCard() {
|
private fun scanCard() {
|
||||||
viewModelScope.launch {
|
modelScope.launch {
|
||||||
cardSdkConfigRepository.isBiometricsRequestPolicy = settingsRepository.shouldSaveAccessCodes()
|
cardSdkConfigRepository.isBiometricsRequestPolicy = settingsRepository.shouldSaveAccessCodes()
|
||||||
|
|
||||||
scanCardProcessor.scan(
|
scanCardProcessor.scan(
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tangem.tap.features.home.api
|
||||||
|
|
||||||
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
|
||||||
|
interface HomeComponent : ComposableContentComponent {
|
||||||
|
|
||||||
|
interface Factory : ComponentFactory<Unit, HomeComponent>
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.tangem.tap.features.home.di
|
||||||
|
|
||||||
|
import com.tangem.core.decompose.model.Model
|
||||||
|
import com.tangem.tap.features.home.DefaultHomeComponent
|
||||||
|
import com.tangem.tap.features.home.HomeModel
|
||||||
|
import com.tangem.tap.features.home.api.HomeComponent
|
||||||
|
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 HomeFeatureModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
fun bindFactory(impl: DefaultHomeComponent.Factory): HomeComponent.Factory
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(HomeModel::class)
|
||||||
|
fun bindModel(model: HomeModel): Model
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRe
|
||||||
import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment
|
import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment
|
||||||
import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment
|
import com.tangem.tap.features.details.ui.securitymode.SecurityModeFragment
|
||||||
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectFragment
|
import com.tangem.tap.features.details.ui.walletconnect.WalletConnectFragment
|
||||||
import com.tangem.tap.features.home.HomeFragment
|
import com.tangem.tap.features.home.api.HomeComponent
|
||||||
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
import com.tangem.tap.features.onboarding.products.note.OnboardingNoteFragment
|
||||||
import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment
|
import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCardsFragment
|
||||||
import com.tangem.tap.features.onboarding.products.twins.ui.OnboardingTwinsFragment
|
import com.tangem.tap.features.onboarding.products.twins.ui.OnboardingTwinsFragment
|
||||||
|
|
@ -61,6 +61,7 @@ internal class ChildFactory @Inject constructor(
|
||||||
private val sendComponentFactory: SendComponent.Factory,
|
private val sendComponentFactory: SendComponent.Factory,
|
||||||
private val stakingComponentFactory: StakingComponent.Factory,
|
private val stakingComponentFactory: StakingComponent.Factory,
|
||||||
private val swapComponentFactory: SwapComponent.Factory,
|
private val swapComponentFactory: SwapComponent.Factory,
|
||||||
|
private val homeComponentFactory: HomeComponent.Factory,
|
||||||
private val tokenDetailsRouter: TokenDetailsRouter,
|
private val tokenDetailsRouter: TokenDetailsRouter,
|
||||||
private val walletRouter: WalletRouter,
|
private val walletRouter: WalletRouter,
|
||||||
private val qrScanningRouter: QrScanningRouter,
|
private val qrScanningRouter: QrScanningRouter,
|
||||||
|
|
@ -249,13 +250,20 @@ internal class ChildFactory @Inject constructor(
|
||||||
componentFactory = sendComponentFactory,
|
componentFactory = sendComponentFactory,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is AppRoute.Home -> {
|
||||||
|
createComponentChild(
|
||||||
|
contextProvider = contextProvider(route, contextFactory),
|
||||||
|
params = Unit,
|
||||||
|
componentFactory = homeComponentFactory,
|
||||||
|
)
|
||||||
|
}
|
||||||
is AppRoute.AccessCodeRecovery,
|
is AppRoute.AccessCodeRecovery,
|
||||||
is AppRoute.AppCurrencySelector,
|
is AppRoute.AppCurrencySelector,
|
||||||
is AppRoute.SaveWallet,
|
is AppRoute.SaveWallet,
|
||||||
is AppRoute.AppSettings,
|
is AppRoute.AppSettings,
|
||||||
is AppRoute.CardSettings,
|
is AppRoute.CardSettings,
|
||||||
is AppRoute.DetailsSecurity,
|
is AppRoute.DetailsSecurity,
|
||||||
is AppRoute.Home,
|
|
||||||
is AppRoute.OnboardingNote,
|
is AppRoute.OnboardingNote,
|
||||||
is AppRoute.OnboardingOther,
|
is AppRoute.OnboardingOther,
|
||||||
is AppRoute.OnboardingTwins,
|
is AppRoute.OnboardingTwins,
|
||||||
|
|
@ -328,7 +336,11 @@ internal class ChildFactory @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is AppRoute.Home -> {
|
is AppRoute.Home -> {
|
||||||
route.asFragmentChild(Provider { HomeFragment() })
|
route.asComponentChild(
|
||||||
|
contextProvider = contextProvider(route, contextFactory),
|
||||||
|
params = Unit,
|
||||||
|
componentFactory = homeComponentFactory,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is AppRoute.ManageTokens -> {
|
is AppRoute.ManageTokens -> {
|
||||||
val source = when (route.source) {
|
val source = when (route.source) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue