Updated on 2026-08-14
This commit is contained in:
commit
7a5933253b
154 changed files with 1767 additions and 1152 deletions
|
|
@ -76,6 +76,7 @@ dependencies {
|
|||
implementation(projects.domain.walletConnect)
|
||||
|
||||
implementation(projects.common)
|
||||
implementation(projects.common.routing)
|
||||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.navigation)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap
|
|||
|
||||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
|
|
@ -28,7 +29,6 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
|||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.features.details.DetailsEntryPoint
|
||||
import com.tangem.features.details.DetailsFeatureToggles
|
||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||
|
|
@ -111,9 +111,9 @@ interface ApplicationEntryPoint {
|
|||
|
||||
fun getDetailsFeatureToggles(): DetailsFeatureToggles
|
||||
|
||||
fun getDetailsEntryPoint(): DetailsEntryPoint
|
||||
|
||||
fun getUrlOpener(): UrlOpener
|
||||
|
||||
fun getShareManager(): ShareManager
|
||||
|
||||
fun getAppRouter(): AppRouter
|
||||
}
|
||||
|
|
@ -3,13 +3,12 @@ package com.tangem.tap
|
|||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import kotlinx.coroutines.*
|
||||
import timber.log.Timber
|
||||
import kotlin.time.Duration
|
||||
|
|
@ -50,7 +49,7 @@ internal class LockUserWalletsTimer(
|
|||
start()
|
||||
|
||||
if (shouldOpenWelcomeScreenOnResume) {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +127,7 @@ internal class LockUserWalletsTimer(
|
|||
if (wasApplicationStopped) {
|
||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = true)
|
||||
} else {
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Welcome))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
|
@ -27,12 +26,16 @@ import androidx.lifecycle.flowWithLifecycle
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.arkivanov.decompose.value.observe
|
||||
import com.arkivanov.essenty.lifecycle.asEssentyLifecycle
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.entity.SerializableIntent
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.di.RootAppComponentContext
|
||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.email.EmailSender
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -60,6 +63,8 @@ import com.tangem.tap.common.DialogManager
|
|||
import com.tangem.tap.common.OnActivityResultCallback
|
||||
import com.tangem.tap.common.SnackbarHandler
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.showFragmentAllowingStateLoss
|
||||
import com.tangem.tap.common.redux.NotificationsHandler
|
||||
import com.tangem.tap.domain.sdk.TangemSdkManager
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
|
|
@ -69,9 +74,10 @@ import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHan
|
|||
import com.tangem.tap.features.main.MainViewModel
|
||||
import com.tangem.tap.features.main.model.Toast
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.features.welcome.ui.WelcomeFragment
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
import com.tangem.tap.routing.RoutingComponent
|
||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -79,7 +85,6 @@ import com.tangem.wallet.databinding.ActivityMainBinding
|
|||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
|
@ -162,6 +167,16 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
lateinit var stakingRouter: StakingRouter
|
||||
|
||||
@Inject
|
||||
@RootAppComponentContext
|
||||
internal lateinit var rootComponentContext: AppComponentContext
|
||||
|
||||
@Inject
|
||||
internal lateinit var appRouterConfig: AppRouterConfig
|
||||
|
||||
@Inject
|
||||
internal lateinit var routingComponentFactory: RoutingComponent.Factory
|
||||
|
||||
internal val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode?>
|
||||
|
|
@ -188,6 +203,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
observeAppThemeModeUpdates()
|
||||
|
||||
setContentView(R.layout.activity_main)
|
||||
installRouting()
|
||||
initContent()
|
||||
|
||||
checkForNotificationPermission()
|
||||
|
|
@ -199,6 +215,31 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
}
|
||||
|
||||
private fun installRouting() {
|
||||
val routingComponent = routingComponentFactory.create(
|
||||
context = rootComponentContext,
|
||||
)
|
||||
|
||||
appRouterConfig.routerScope = lifecycleScope
|
||||
appRouterConfig.componentRouter = routingComponent.router
|
||||
|
||||
routingComponent.stack.observe(lifecycle.asEssentyLifecycle()) { childStack ->
|
||||
appRouterConfig.stack = childStack.backStack
|
||||
.plus(childStack.active)
|
||||
.map { it.configuration }
|
||||
|
||||
when (val child = childStack.active.instance) {
|
||||
is RoutingComponent.Child.Initial -> Unit
|
||||
is RoutingComponent.Child.LegacyFragment -> {
|
||||
supportFragmentManager.showFragmentAllowingStateLoss(child.name, child.fragmentProvider)
|
||||
}
|
||||
is RoutingComponent.Child.LegacyIntent -> {
|
||||
startActivity(child.intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeStateUpdates() {
|
||||
viewModel.state
|
||||
.flowWithLifecycle(lifecycle)
|
||||
|
|
@ -220,8 +261,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
|
||||
private fun installActivityDependencies() {
|
||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
||||
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
tangemSdkManager = injectedTangemSdkManager
|
||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||
|
|
@ -335,7 +374,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this)))
|
||||
intentProcessor.removeAll()
|
||||
cardSdkLifecycleObserver.onDestroy(this)
|
||||
super.onDestroy()
|
||||
|
|
@ -477,16 +515,11 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
private fun navigateToInitialScreen(intentWhichStartedActivity: Intent?) {
|
||||
if (userWalletsListManager.isLockable && userWalletsListManager.hasUserWallets) {
|
||||
store.dispatch(
|
||||
NavigationAction.NavigateTo(
|
||||
screen = AppScreen.Welcome,
|
||||
bundle = intentWhichStartedActivity?.let {
|
||||
bundleOf(WelcomeFragment.INITIAL_INTENT_KEY to it)
|
||||
},
|
||||
),
|
||||
)
|
||||
store.dispatchNavigationAction {
|
||||
replaceAll(AppRoute.Welcome(intentWhichStartedActivity?.let(::SerializableIntent)))
|
||||
}
|
||||
} else {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Home) }
|
||||
lifecycleScope.launch {
|
||||
intentProcessor.handleIntent(intentWhichStartedActivity, false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.LogFormat
|
|||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||
|
|
@ -43,7 +44,6 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
|||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.features.details.DetailsEntryPoint
|
||||
import com.tangem.features.details.DetailsFeatureToggles
|
||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||
|
|
@ -185,14 +185,14 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
private val detailsFeatureToggles: DetailsFeatureToggles
|
||||
get() = entryPoint.getDetailsFeatureToggles()
|
||||
|
||||
private val detailsEntryPoint: DetailsEntryPoint
|
||||
get() = entryPoint.getDetailsEntryPoint()
|
||||
|
||||
private val urlOpener
|
||||
get() = entryPoint.getUrlOpener()
|
||||
|
||||
private val shareManager
|
||||
get() = entryPoint.getShareManager()
|
||||
|
||||
private val appRouter: AppRouter
|
||||
get() = entryPoint.getAppRouter()
|
||||
// endregion
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
@ -281,9 +281,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
blockchainSDKFactory = blockchainSDKFactory,
|
||||
saveBlockchainErrorUseCase = saveBlockchainErrorUseCase,
|
||||
detailsFeatureToggles = detailsFeatureToggles,
|
||||
detailsEntryPoint = detailsEntryPoint,
|
||||
urlOpener = urlOpener,
|
||||
shareManager = shareManager,
|
||||
appRouter = appRouter,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,172 +1,51 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.*
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.FragmentShareTransition
|
||||
import com.tangem.feature.referral.ReferralFragment
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.AddCustomTokenFragment
|
||||
import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorFragment
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRecoveryFragment
|
||||
import com.tangem.tap.features.details.ui.details.DetailsFragment
|
||||
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.walletconnect.WalletConnectFragment
|
||||
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
|
||||
import com.tangem.tap.features.home.HomeFragment
|
||||
import com.tangem.tap.features.main.ui.ModalNotificationBottomSheetFragment
|
||||
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.twins.ui.OnboardingTwinsFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.tokens.impl.presentation.TokensListFragment
|
||||
import com.tangem.tap.features.welcome.ui.WelcomeFragment
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.wallet.R
|
||||
import timber.log.Timber
|
||||
|
||||
fun FragmentActivity.openFragment(
|
||||
screen: AppScreen,
|
||||
addToBackstack: Boolean,
|
||||
bundle: Bundle? = null,
|
||||
fgShareTransition: FragmentShareTransition? = null,
|
||||
) {
|
||||
val transaction = supportFragmentManager.beginTransaction().apply {
|
||||
setReorderingAllowed(true)
|
||||
}
|
||||
fun FragmentManager.showFragmentAllowingStateLoss(name: String, fragmentProvider: Provider<Fragment>) {
|
||||
Timber.d("Showing $name route")
|
||||
|
||||
val fragment = fragmentFactory(screen).apply {
|
||||
arguments = bundle
|
||||
val isPoppedBack = popBackStackImmediate(name, 0)
|
||||
|
||||
if (fgShareTransition != null) {
|
||||
sharedElementEnterTransition = fgShareTransition.enterTransitionSet
|
||||
sharedElementReturnTransition = fgShareTransition.exitTransitionSet
|
||||
fgShareTransition.shareElements.forEach { shareElement ->
|
||||
shareElement.wView.get()?.let { view ->
|
||||
transaction.addSharedElement(view, shareElement.elementName)
|
||||
}
|
||||
}
|
||||
if (!isPoppedBack) {
|
||||
val fragment = fragmentProvider()
|
||||
|
||||
if (fragment is DialogFragment) {
|
||||
fragment.showDialog(fragmentManager = this, name)
|
||||
} else {
|
||||
fragment.showFragment(fragmentManager = this, name)
|
||||
}
|
||||
}
|
||||
|
||||
if (screen.isDialogFragment && fragment is DialogFragment) {
|
||||
fragment.showAllowingStateLoss(
|
||||
fragmentManager = supportFragmentManager,
|
||||
baseTransaction = transaction,
|
||||
tag = screen.name,
|
||||
addToBackstack = addToBackstack,
|
||||
)
|
||||
Timber.d("Route $name is shown")
|
||||
} else {
|
||||
transaction.replace(R.id.fragment_container, fragment, screen.name)
|
||||
if (addToBackstack) {
|
||||
transaction.addToBackStack(screen.name)
|
||||
}
|
||||
Timber.d("Route $name is found in backstack and shown")
|
||||
}
|
||||
}
|
||||
|
||||
private fun DialogFragment.showDialog(fragmentManager: FragmentManager, name: String) {
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
||||
try {
|
||||
transaction.addToBackStack(name)
|
||||
show(transaction, name)
|
||||
} catch (e: IllegalStateException) {
|
||||
transaction.add(this, name)
|
||||
transaction.addToBackStack(name)
|
||||
|
||||
transaction.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun DialogFragment.showAllowingStateLoss(
|
||||
fragmentManager: FragmentManager,
|
||||
baseTransaction: FragmentTransaction,
|
||||
tag: String,
|
||||
addToBackstack: Boolean,
|
||||
) {
|
||||
runCatching {
|
||||
if (addToBackstack) baseTransaction.addToBackStack(tag)
|
||||
show(baseTransaction, tag)
|
||||
}
|
||||
.onFailure { throwable ->
|
||||
if (throwable is IllegalStateException) {
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
transaction.add(this, tag)
|
||||
if (addToBackstack) transaction.addToBackStack(tag)
|
||||
private fun Fragment.showFragment(fragmentManager: FragmentManager, name: String) {
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
||||
transaction.commitAllowingStateLoss()
|
||||
} else {
|
||||
Timber.e(throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.replace(R.id.fragment_container, this, name)
|
||||
transaction.addToBackStack(name)
|
||||
|
||||
fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) {
|
||||
val inclusiveFlag = if (inclusive) FragmentManager.POP_BACK_STACK_INCLUSIVE else 0
|
||||
try {
|
||||
this.supportFragmentManager.popBackStack(screen?.name, inclusiveFlag)
|
||||
} catch (e: IllegalStateException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun FragmentActivity.getPreviousScreen(): AppScreen? {
|
||||
val indexOfLastFragment = if (this.supportFragmentManager.backStackEntryCount > 0) {
|
||||
this.supportFragmentManager.backStackEntryCount - 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
val tag = if (indexOfLastFragment < this.supportFragmentManager.backStackEntryCount) {
|
||||
this.supportFragmentManager.getBackStackEntryAt(indexOfLastFragment).name
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return tag?.let { AppScreen.valueOf(tag) }
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod", "LongMethod")
|
||||
private fun fragmentFactory(screen: AppScreen): Fragment {
|
||||
return when (screen) {
|
||||
AppScreen.Home -> HomeFragment()
|
||||
AppScreen.OnboardingNote -> OnboardingNoteFragment()
|
||||
AppScreen.OnboardingWallet -> OnboardingWalletFragment()
|
||||
AppScreen.OnboardingTwins -> OnboardingTwinsFragment()
|
||||
AppScreen.OnboardingOther -> OnboardingOtherCardsFragment()
|
||||
AppScreen.Wallet -> {
|
||||
store.inject(getDependency = DaggerGraphState::walletRouter).getEntryFragment()
|
||||
}
|
||||
AppScreen.Send -> {
|
||||
val featureToggles = store.inject(getDependency = DaggerGraphState::sendFeatureToggles)
|
||||
|
||||
if (featureToggles.isRedesignedSendEnabled) {
|
||||
store.inject(getDependency = DaggerGraphState::sendRouter).getEntryFragment()
|
||||
} else {
|
||||
SendFragment()
|
||||
}
|
||||
}
|
||||
AppScreen.Details -> {
|
||||
val featureToggles = store.inject(getDependency = DaggerGraphState::detailsFeatureToggles)
|
||||
|
||||
if (featureToggles.isRedesignEnabled) {
|
||||
store.inject(DaggerGraphState::detailsEntryPoint).entryFragment()
|
||||
} else {
|
||||
DetailsFragment()
|
||||
}
|
||||
}
|
||||
AppScreen.DetailsSecurity -> SecurityModeFragment()
|
||||
AppScreen.CardSettings -> CardSettingsFragment()
|
||||
AppScreen.AppSettings -> AppSettingsFragment()
|
||||
AppScreen.ResetToFactory -> ResetCardFragment()
|
||||
AppScreen.AccessCodeRecovery -> AccessCodeRecoveryFragment()
|
||||
AppScreen.Disclaimer -> DisclaimerFragment()
|
||||
AppScreen.ManageTokens -> TokensListFragment()
|
||||
AppScreen.AddCustomToken -> AddCustomTokenFragment()
|
||||
AppScreen.WalletDetails -> {
|
||||
store.inject(getDependency = DaggerGraphState::tokenDetailsRouter).getEntryFragment()
|
||||
}
|
||||
AppScreen.WalletConnectSessions -> WalletConnectFragment()
|
||||
AppScreen.QrScanning -> {
|
||||
store.inject(getDependency = DaggerGraphState::qrScanningRouter).getEntryFragment()
|
||||
}
|
||||
AppScreen.ReferralProgram -> ReferralFragment()
|
||||
AppScreen.Swap -> SwapFragment()
|
||||
AppScreen.Welcome -> WelcomeFragment()
|
||||
AppScreen.SaveWallet -> SaveWalletBottomSheetFragment()
|
||||
AppScreen.AppCurrencySelector -> AppCurrencySelectorFragment()
|
||||
AppScreen.ModalNotification -> ModalNotificationBottomSheetFragment()
|
||||
AppScreen.Staking -> store.inject(getDependency = DaggerGraphState::stakingRouter).getEntryFragment()
|
||||
}
|
||||
transaction.commitAllowingStateLoss()
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -89,6 +90,10 @@ fun Store<AppState>.dispatchShare(url: String) {
|
|||
inject(DaggerGraphState::shareManager).shareText(url)
|
||||
}
|
||||
|
||||
fun Store<AppState>.dispatchNavigationAction(action: AppRouter.() -> Unit) {
|
||||
inject(DaggerGraphState::appRouter).action()
|
||||
}
|
||||
|
||||
inline fun <reified T> Store<AppState>.inject(getDependency: DaggerGraphState.() -> T?): T {
|
||||
return requireNotNull(state.daggerGraphState.getDependency()) {
|
||||
"${T::class.simpleName} isn't initialized "
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.common.redux.global.globalReducer
|
||||
import com.tangem.tap.common.redux.navigation.NavigationReducer
|
||||
import com.tangem.tap.features.details.redux.DetailsReducer
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer
|
||||
|
|
@ -23,7 +22,6 @@ fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder)
|
|||
if (action is AppAction.RestoreState) return action.state
|
||||
|
||||
return AppState(
|
||||
navigationState = NavigationReducer.reduce(action, state),
|
||||
globalState = globalReducer(action, state, appStateHolder),
|
||||
homeState = HomeReducer.reduce(action, state),
|
||||
onboardingNoteState = OnboardingNoteReducer.reduce(action, state),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.core.navigation.NavigationState
|
||||
import com.tangem.domain.redux.DomainState
|
||||
import com.tangem.domain.redux.domainStore
|
||||
import com.tangem.domain.redux.global.NetworkServices
|
||||
import com.tangem.tap.common.redux.global.GlobalMiddleware
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.redux.legacy.LegacyMiddleware
|
||||
import com.tangem.tap.common.redux.navigation.navigationMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware
|
||||
|
|
@ -40,7 +38,6 @@ import org.rekotlin.Middleware
|
|||
import org.rekotlin.StateType
|
||||
|
||||
data class AppState(
|
||||
val navigationState: NavigationState = NavigationState(),
|
||||
val globalState: GlobalState = GlobalState(),
|
||||
val homeState: HomeState = HomeState(),
|
||||
val onboardingNoteState: OnboardingNoteState = OnboardingNoteState(),
|
||||
|
|
@ -73,7 +70,6 @@ data class AppState(
|
|||
fun getMiddleware(): List<Middleware<AppState>> {
|
||||
return listOf(
|
||||
logMiddleware,
|
||||
navigationMiddleware,
|
||||
notificationsMiddleware,
|
||||
GlobalMiddleware.handler,
|
||||
HomeMiddleware.handler,
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
package com.tangem.tap.common.redux.navigation
|
||||
|
||||
import android.content.Intent
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.openFragment
|
||||
import com.tangem.tap.common.extensions.popBackTo
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
val navigationMiddleware: Middleware<AppState> = { _, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
if (action is NavigationAction) {
|
||||
val navState = state()?.navigationState
|
||||
when (action) {
|
||||
is NavigationAction.NavigateTo -> {
|
||||
navState?.activity?.get()?.openFragment(
|
||||
screen = action.screen,
|
||||
addToBackstack = action.addToBackstack,
|
||||
fgShareTransition = action.fragmentShareTransition,
|
||||
bundle = action.bundle,
|
||||
)
|
||||
}
|
||||
is NavigationAction.PopBackTo -> {
|
||||
if (navState?.backStack?.lastOrNull() != action.screen) {
|
||||
when (val screen = action.screen) {
|
||||
AppScreen.Home,
|
||||
AppScreen.Welcome,
|
||||
-> {
|
||||
if (navState?.backStack?.contains(screen) == false) {
|
||||
// Pop back to activity
|
||||
navState.activity?.get()?.popBackTo(screen = null, inclusive = true)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen))
|
||||
} else {
|
||||
navState?.activity?.get()?.popBackTo(screen, action.inclusive)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
navState?.activity?.get()?.popBackTo(screen, action.inclusive)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is NavigationAction.OpenDocument -> {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.data = action.url
|
||||
navState?.activity?.get()?.startActivity(intent)
|
||||
}
|
||||
is NavigationAction.ActivityCreated,
|
||||
is NavigationAction.ActivityDestroyed,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.tap.common.redux.navigation
|
||||
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.NavigationState
|
||||
import com.tangem.tap.common.extensions.getPreviousScreen
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Action
|
||||
|
||||
object NavigationReducer {
|
||||
fun reduce(action: Action, state: AppState): NavigationState = internalReduce(action, state)
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, state: AppState): NavigationState {
|
||||
val navigationAction = action as? NavigationAction ?: return state.navigationState
|
||||
val navState = state.navigationState
|
||||
|
||||
return when (navigationAction) {
|
||||
is NavigationAction.NavigateTo -> {
|
||||
navState.copy(backStack = navState.backStack + navigationAction.screen)
|
||||
}
|
||||
is NavigationAction.PopBackTo -> {
|
||||
if (navState.backStack.lastOrNull() == navigationAction.screen) return navState
|
||||
|
||||
val screen = navigationAction.screen ?: navState.activity?.get()?.getPreviousScreen()
|
||||
val index = navState.backStack.lastIndexOf(screen) + 1
|
||||
state.navigationState.copy(backStack = navState.backStack.subList(0, index))
|
||||
}
|
||||
is NavigationAction.ActivityCreated -> navState.copy(activity = navigationAction.activity)
|
||||
is NavigationAction.ActivityDestroyed -> {
|
||||
when {
|
||||
// Destroy the activity if it invoked for the same activity. Prevents overwriting to null if there is a
|
||||
// new scan from the background [REDACTED_TASK_KEY]
|
||||
navState.activity?.get() == navigationAction.activity.get() -> navState.copy(activity = null)
|
||||
else -> navState
|
||||
}
|
||||
}
|
||||
else -> navState
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.core.navigation.ReduxNavController
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import dagger.Binds
|
||||
|
|
@ -13,10 +12,6 @@ import javax.inject.Singleton
|
|||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AppStateHolderModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindsNavigationStateHolder(appStateHolder: AppStateHolder): ReduxNavController
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindsReduxStateHolder(appStateHolder: AppStateHolder): ReduxStateHolder
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.tap.di.routing
|
||||
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.tap.routing.ProxyAppRouter
|
||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||
import com.tangem.tap.routing.configurator.MutableAppRouterConfig
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AppRouterModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppRouter(config: AppRouterConfig, dispatchers: CoroutineDispatcherProvider): AppRouter =
|
||||
ProxyAppRouter(config, dispatchers)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppRouterConfigurator(): AppRouterConfig = MutableAppRouterConfig()
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.di.routing
|
||||
|
||||
import com.tangem.tap.routing.RoutingComponent
|
||||
import com.tangem.tap.routing.impl.DefaultRoutingComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ActivityComponent::class)
|
||||
internal interface RoutingComponentModule {
|
||||
|
||||
@Binds
|
||||
@ActivityScoped
|
||||
fun bindRoutingComponentFactory(factory: DefaultRoutingComponent.Factory): RoutingComponent.Factory
|
||||
}
|
||||
|
|
@ -5,12 +5,11 @@ import com.tangem.common.core.TangemError
|
|||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
|
|
@ -21,6 +20,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
||||
|
|
@ -118,7 +118,7 @@ internal object LegacyScanProcessor {
|
|||
disclaimerWillShow()
|
||||
store.dispatchWithMain(
|
||||
DisclaimerAction.Show(
|
||||
fromScreen = AppScreen.Home,
|
||||
from = DisclaimerSource.Home,
|
||||
callback = DisclaimerCallback(
|
||||
onAccept = {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
|
|
@ -170,7 +170,7 @@ internal object LegacyScanProcessor {
|
|||
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
||||
onWalletNotCreated()
|
||||
store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse)))
|
||||
navigateTo(AppScreen.OnboardingTwins) { onProgressStateChange(it) }
|
||||
navigateTo(AppRoute.OnboardingTwins) { onProgressStateChange(it) }
|
||||
} else {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
onSuccess(scanResponse)
|
||||
|
|
@ -178,9 +178,9 @@ internal object LegacyScanProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend inline fun navigateTo(screen: AppScreen, onProgressStateChange: (showProgress: Boolean) -> Unit) {
|
||||
private suspend inline fun navigateTo(route: AppRoute, onProgressStateChange: (showProgress: Boolean) -> Unit) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen))
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
onProgressStateChange(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,16 +3,15 @@ package com.tangem.tap.domain.scanCard
|
|||
import arrow.fx.coroutines.resourceScope
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.domain.scanCard.chains.*
|
||||
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
||||
|
|
@ -132,8 +131,8 @@ internal object UseCaseScanProcessor {
|
|||
action()
|
||||
}
|
||||
|
||||
private suspend inline fun navigateTo(screen: AppScreen) {
|
||||
private suspend inline fun navigateTo(route: AppRoute) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen))
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
|
|
@ -55,8 +55,8 @@ class CheckForOnboardingChain(
|
|||
canSkipBackup = previousChainResult.card.canSkipBackup,
|
||||
),
|
||||
)
|
||||
val appScreen = OnboardingHelper.whereToNavigate(previousChainResult)
|
||||
ScanChainException.OnboardingNeeded(appScreen).left()
|
||||
val route = OnboardingHelper.whereToNavigate(previousChainResult)
|
||||
ScanChainException.OnboardingNeeded(route).left()
|
||||
}
|
||||
else -> {
|
||||
Analytics.setContext(previousChainResult)
|
||||
|
|
@ -69,7 +69,7 @@ class CheckForOnboardingChain(
|
|||
store.dispatchOnMain(
|
||||
TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(previousChainResult)),
|
||||
)
|
||||
ScanChainException.OnboardingNeeded(AppScreen.OnboardingTwins).left()
|
||||
ScanChainException.OnboardingNeeded(AppRoute.OnboardingTwins).left()
|
||||
} else {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
previousChainResult.right()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.core.chain.ResultChain
|
||||
|
|
@ -13,6 +12,7 @@ import com.tangem.tap.features.disclaimer.Disclaimer
|
|||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import org.rekotlin.Store
|
||||
import kotlin.coroutines.resume
|
||||
|
|
@ -50,7 +50,7 @@ internal class DisclaimerChain(
|
|||
return suspendCancellableCoroutine { continuation ->
|
||||
store.dispatchOnMain(
|
||||
DisclaimerAction.Show(
|
||||
fromScreen = AppScreen.Home,
|
||||
from = DisclaimerSource.Home,
|
||||
callback = DisclaimerCallback(
|
||||
onAccept = {
|
||||
if (continuation.isActive) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.domain.scanCard.chains
|
||||
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
|
||||
sealed class ScanChainException : ScanCardException.ChainException() {
|
||||
|
|
@ -19,5 +19,5 @@ sealed class ScanChainException : ScanCardException.ChainException() {
|
|||
*
|
||||
* @param onboardingRoute route where to navigate
|
||||
* */
|
||||
data class OnboardingNeeded(val onboardingRoute: AppScreen) : ScanChainException()
|
||||
data class OnboardingNeeded(val onboardingRoute: AppRoute) : ScanChainException()
|
||||
}
|
||||
|
|
@ -14,7 +14,8 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.transition.TransitionInflater
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ abstract class BaseFragment(layoutId: Int) : Fragment(layoutId), FragmentOnBackP
|
|||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.tap.features.customtoken.impl.presentation.routers
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -12,11 +14,11 @@ import com.tangem.wallet.R
|
|||
internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
||||
|
||||
override fun popBackStack() {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
}
|
||||
|
||||
override fun openWalletScreen() {
|
||||
store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
}
|
||||
|
||||
override fun openUnsupportedNetworkAlert(blockchain: Blockchain) {
|
||||
|
|
@ -32,7 +34,7 @@ internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
|||
val alert = AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_error,
|
||||
messageId = R.string.common_unknown_error,
|
||||
onOk = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
onOk = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
store.dispatchDialogShow(alert)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ import com.tangem.common.*
|
|||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.core.UserCodeRequestPolicy
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
|
|
@ -70,7 +72,8 @@ class DetailsMiddleware {
|
|||
is DetailsAction.AppSettings -> appSettingsMiddleware.handle(state, action)
|
||||
is DetailsAction.ReCreateTwinsWallet -> {
|
||||
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingTwins))
|
||||
|
||||
store.dispatchNavigationAction { push(AppRoute.OnboardingTwins) }
|
||||
}
|
||||
is DetailsAction.AccessCodeRecovery -> accessCodeRecoveryMiddleware.handle(state, action)
|
||||
is DetailsAction.ScanCard -> scanCard(state)
|
||||
|
|
@ -90,7 +93,7 @@ class DetailsMiddleware {
|
|||
store.dispatch(DetailsAction.ReCreateTwinsWallet)
|
||||
return
|
||||
} else {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.ResetToFactory))
|
||||
store.dispatchNavigationAction { push(AppRoute.ResetToFactory) }
|
||||
}
|
||||
}
|
||||
is DetailsAction.ResetToFactory.Proceed -> {
|
||||
|
|
@ -131,15 +134,15 @@ class DetailsMiddleware {
|
|||
|
||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync
|
||||
if (selectedUserWallet != null) {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
store.onUserWalletSelected(selectedUserWallet)
|
||||
} else {
|
||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
||||
.fold(onSuccess = { true }, onFailure = { false })
|
||||
if (isLocked && userWalletsListManager.hasUserWallets) {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome))
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
} else {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Home) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,7 +166,7 @@ class DetailsMiddleware {
|
|||
fun handle(action: DetailsAction.ManageSecurity, detailsState: DetailsState) {
|
||||
when (action) {
|
||||
is DetailsAction.ManageSecurity.OpenSecurity -> {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsSecurity))
|
||||
store.dispatchNavigationAction { push(AppRoute.DetailsSecurity) }
|
||||
}
|
||||
is DetailsAction.ManageSecurity.SaveChanges -> {
|
||||
val cardSettingsState = detailsState.cardSettingsState
|
||||
|
|
@ -182,7 +185,7 @@ class DetailsMiddleware {
|
|||
is CompletionResult.Success -> {
|
||||
Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue))
|
||||
store.dispatch(GlobalAction.UpdateSecurityOptions(selectedOption))
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
|
|
@ -392,7 +395,7 @@ class DetailsMiddleware {
|
|||
deleteSavedAccessCodes()
|
||||
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false)
|
||||
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Home>() }
|
||||
|
||||
return CompletionResult.Success(Unit)
|
||||
}
|
||||
|
|
@ -431,7 +434,7 @@ class DetailsMiddleware {
|
|||
when (action) {
|
||||
is DetailsAction.AccessCodeRecovery.Open -> {
|
||||
Analytics.send(Settings.CardSettings.AccessCodeRecoveryButton())
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AccessCodeRecovery))
|
||||
store.dispatchNavigationAction { push(AppRoute.AccessCodeRecovery) }
|
||||
}
|
||||
is DetailsAction.AccessCodeRecovery.SaveChanges -> {
|
||||
scope.launch {
|
||||
|
|
@ -443,7 +446,7 @@ class DetailsMiddleware {
|
|||
AnalyticsParam.AccessCodeRecoveryStatus.from(action.enabled),
|
||||
),
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
store.dispatchOnMain(
|
||||
DetailsAction.AccessCodeRecovery.SaveChanges.Success(action.enabled),
|
||||
)
|
||||
|
|
@ -502,7 +505,7 @@ class DetailsMiddleware {
|
|||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||
},
|
||||
disclaimerWillShow = {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
onSuccess = { scanResponse ->
|
||||
createUserWallet(scanResponse)
|
||||
|
|
@ -546,7 +549,7 @@ class DetailsMiddleware {
|
|||
store.onUserWalletSelected(userWallet)
|
||||
|
||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
if (error is UserWalletsListError.WalletAlreadySaved) {
|
||||
|
|
@ -554,7 +557,7 @@ class DetailsMiddleware {
|
|||
store.onUserWalletSelected(userWallet)
|
||||
|
||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
} else {
|
||||
Timber.e(error, "Unable to create user wallet")
|
||||
handleError(error, prevUseBiometricsForAccessCode)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
|
|
@ -69,10 +69,12 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
}
|
||||
|
||||
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: AppState): DetailsState {
|
||||
val router = store.inject(DaggerGraphState::appRouter)
|
||||
|
||||
return DetailsState(
|
||||
scanResponse = action.scanResponse,
|
||||
// If the current screen is ResetToFactory, we must save the ResetToFactory's state
|
||||
cardSettingsState = if (store.state.navigationState.backStack.lastOrNull() == AppScreen.ResetToFactory) {
|
||||
cardSettingsState = if (router.stack.lastOrNull() is AppRoute.ResetToFactory) {
|
||||
state.detailsState.cardSettingsState
|
||||
} else {
|
||||
null
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
package com.tangem.tap.features.details.redux.walletconnect
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.Account
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError
|
||||
|
|
@ -62,14 +60,7 @@ class WalletConnectMiddleware {
|
|||
// TODO check
|
||||
store.dispatchOnMain(WalletConnectAction.ShowClipboardOrScanQrDialog(uri))
|
||||
} else {
|
||||
store.dispatchOnMain(
|
||||
NavigationAction.NavigateTo(
|
||||
screen = AppScreen.QrScanning,
|
||||
bundle = bundleOf(
|
||||
QrScanningRouter.SOURCE_KEY to SourceType.WALLET_CONNECT,
|
||||
),
|
||||
),
|
||||
)
|
||||
store.dispatchNavigationAction { push(AppRoute.QrScanning(SourceType.WALLET_CONNECT)) }
|
||||
}
|
||||
}
|
||||
is WalletConnectAction.ShowClipboardOrScanQrDialog -> {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package com.tangem.tap.features.details.ui.appcurrency
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.navigation.ReduxNavController
|
||||
|
||||
import com.tangem.domain.appcurrency.GetAvailableCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.SelectAppCurrencyUseCase
|
||||
|
|
@ -20,7 +21,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
|||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getAvailableCurrenciesUseCase: GetAvailableCurrenciesUseCase,
|
||||
private val selectAppCurrencyUseCase: SelectAppCurrencyUseCase,
|
||||
private val reduxNavController: ReduxNavController,
|
||||
private val router: AppRouter,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : ViewModel(), AppCurrencySelectorIntents {
|
||||
|
|
@ -34,7 +35,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
|||
val uiState: StateFlow<AppCurrencySelectorState> = stateController.stateFlow
|
||||
|
||||
override fun onBackClick() {
|
||||
reduxNavController.popBackStack()
|
||||
router.pop()
|
||||
}
|
||||
|
||||
override fun onSearchClick() {
|
||||
|
|
@ -52,7 +53,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
|||
analyticsEventHandler.send(
|
||||
event = Settings.AppSettings.MainCurrencyChanged(currencyType = currency.name),
|
||||
)
|
||||
reduxNavController.popBackStack()
|
||||
router.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRouter
|
||||
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -36,7 +38,7 @@ internal class AppSettingsFragment : ComposeFragment() {
|
|||
state = state,
|
||||
onBackClick = {
|
||||
store.dispatch(DetailsAction.ResetCardSettingsData)
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import androidx.lifecycle.DefaultLifecycleObserver
|
|||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.features.details.redux.AppSetting
|
||||
|
|
@ -128,7 +129,7 @@ internal class AppSettingsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun showAppCurrencySelector() {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.AppCurrencySelector))
|
||||
store.dispatchNavigationAction { push(AppRoute.AppCurrencySelector) }
|
||||
}
|
||||
|
||||
private fun showThemeModeSelector(selectedMode: AppThemeMode) {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRouter
|
||||
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -29,7 +31,7 @@ internal class CardSettingsFragment : ComposeFragment() {
|
|||
state = viewModel.screenState.value,
|
||||
onBackClick = {
|
||||
store.dispatch(DetailsAction.ResetCardSettingsData)
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -28,7 +29,7 @@ class AccessCodeRecoveryFragment : ComposeFragment(), StoreSubscriber<DetailsSta
|
|||
override fun ScreenContent(modifier: Modifier) {
|
||||
AccessCodeRecoveryScreen(
|
||||
state = screenState.value,
|
||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ package com.tangem.tap.features.details.ui.details
|
|||
import android.os.Bundle
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -45,7 +46,7 @@ internal class DetailsFragment : ComposeFragment(), StoreSubscriber<DetailsState
|
|||
DetailsScreen(
|
||||
modifier = modifier,
|
||||
state = detailsViewModel.detailsScreenState.value,
|
||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ package com.tangem.tap.features.details.ui.details
|
|||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
|
|
@ -16,16 +16,14 @@ import com.tangem.domain.common.util.cardTypesResolver
|
|||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.addContext
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.feedback.FeedbackEmail
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
|
||||
import com.tangem.tap.features.home.LocaleRegionProvider
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.scope
|
||||
|
|
@ -129,15 +127,17 @@ internal class DetailsViewModel(
|
|||
}
|
||||
|
||||
private fun navigateToTesterMenu() {
|
||||
store.state.daggerGraphState.testerRouter?.startTesterScreen()
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.TesterMenu)
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToToS() {
|
||||
store.dispatchOnMain(DisclaimerAction.Show(AppScreen.Details))
|
||||
store.dispatchOnMain(DisclaimerAction.Show(DisclaimerSource.Details))
|
||||
}
|
||||
|
||||
private fun navigateToReferralProgram() {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.ReferralProgram))
|
||||
store.dispatchNavigationAction { push(AppRoute.ReferralProgram) }
|
||||
}
|
||||
|
||||
private fun sendFeedback() {
|
||||
|
|
@ -147,12 +147,12 @@ internal class DetailsViewModel(
|
|||
|
||||
private fun navigateToAppSettings() {
|
||||
Analytics.send(Settings.ButtonAppSettings())
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.AppSettings))
|
||||
store.dispatchNavigationAction { push(AppRoute.AppSettings) }
|
||||
}
|
||||
|
||||
private fun navigateToCardSettings() {
|
||||
Analytics.send(Settings.ButtonCardSettings())
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.CardSettings))
|
||||
store.dispatchNavigationAction { push(AppRoute.CardSettings) }
|
||||
}
|
||||
|
||||
private fun linkMoreCards() {
|
||||
|
|
@ -165,7 +165,7 @@ internal class DetailsViewModel(
|
|||
val scanResponse = selectedUserWallet.scanResponse
|
||||
Analytics.addContext(scanResponse)
|
||||
store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
||||
store.dispatchNavigationAction { push(AppRoute.OnboardingWallet()) }
|
||||
}
|
||||
|
||||
private fun scanAndSaveUserWallet() {
|
||||
|
|
@ -175,7 +175,7 @@ internal class DetailsViewModel(
|
|||
|
||||
private fun navigateToWalletConnect() {
|
||||
Analytics.send(Settings.ButtonWalletConnect())
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
|
||||
store.dispatchNavigationAction { push(AppRoute.WalletConnectSessions) }
|
||||
}
|
||||
|
||||
private fun handleSocialNetworkClick(link: SocialNetworkLink) {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -30,7 +31,7 @@ internal class ResetCardFragment : ComposeFragment(), StoreSubscriber<DetailsSta
|
|||
|
||||
ResetCardScreen(
|
||||
state = state,
|
||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@ package com.tangem.tap.features.details.ui.resetcard
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
|
||||
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||
import com.tangem.domain.card.ResetCardUseCase
|
||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.features.details.redux.CardSettingsState
|
||||
import com.tangem.tap.features.details.redux.DetailsAction.ResetToFactory
|
||||
|
|
@ -165,9 +167,9 @@ internal class ResetCardViewModel @Inject constructor(
|
|||
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrNull()
|
||||
|
||||
if (newSelectedWallet != null) {
|
||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
} else {
|
||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Home>() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -29,7 +30,7 @@ internal class SecurityModeFragment : ComposeFragment(), StoreSubscriber<Details
|
|||
SecurityModeScreen(
|
||||
modifier = modifier,
|
||||
state = screenState.value,
|
||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import androidx.compose.runtime.MutableState
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -41,7 +42,7 @@ internal class WalletConnectFragment : ComposeFragment(), StoreSubscriber<Wallet
|
|||
modifier = modifier,
|
||||
state = state,
|
||||
onBackClick = {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@ package com.tangem.tap.features.details.ui.walletconnect.dialogs
|
|||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -22,14 +20,9 @@ object ClipboardOrScanQrDialog {
|
|||
store.dispatch(WalletConnectAction.OpenSession(wcUri))
|
||||
}
|
||||
setNegativeButton(context.getText(R.string.wallet_connect_scan_new_code)) { _, _ ->
|
||||
store.dispatch(
|
||||
NavigationAction.NavigateTo(
|
||||
screen = AppScreen.QrScanning,
|
||||
bundle = bundleOf(
|
||||
QrScanningRouter.SOURCE_KEY to SourceType.WALLET_CONNECT,
|
||||
),
|
||||
),
|
||||
)
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.QrScanning(source = SourceType.WALLET_CONNECT))
|
||||
}
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.tap.common.entities.ProgressState
|
||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -10,7 +9,7 @@ sealed class DisclaimerAction : Action {
|
|||
data class SetDisclaimer(val disclaimer: Disclaimer) : DisclaimerAction()
|
||||
|
||||
data class Show(
|
||||
val fromScreen: AppScreen,
|
||||
val from: DisclaimerSource,
|
||||
val callback: DisclaimerCallback? = null,
|
||||
) : DisclaimerAction()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -25,17 +26,19 @@ private fun handleDisclaimerMiddleware(action: Action, appState: AppState) {
|
|||
|
||||
when (action) {
|
||||
is DisclaimerAction.Show -> {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.Disclaimer(isTosAccepted = action.from == DisclaimerSource.Details))
|
||||
}
|
||||
}
|
||||
is DisclaimerAction.AcceptDisclaimer -> {
|
||||
mainScope.launch {
|
||||
state.disclaimer.accept()
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
state.callback?.onAccept?.invoke()
|
||||
}
|
||||
}
|
||||
is DisclaimerAction.OnBackPressed -> {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
state.callback?.onDismiss?.invoke()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ private fun internalReduce(action: Action, state: AppState): DisclaimerState {
|
|||
disclaimer = action.disclaimer,
|
||||
)
|
||||
is DisclaimerAction.Show -> disclaimerState.copy(
|
||||
showedFromScreen = action.fromScreen,
|
||||
showedFrom = action.from,
|
||||
callback = action.callback,
|
||||
)
|
||||
is DisclaimerAction.AcceptDisclaimer, is DisclaimerAction.OnBackPressed -> disclaimerState.copy(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
enum class DisclaimerSource {
|
||||
Home, Details
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.disclaimer.redux
|
||||
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
|
||||
import com.tangem.tap.common.entities.ProgressState
|
||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||
import com.tangem.tap.features.disclaimer.DummyDisclaimer
|
||||
|
|
@ -9,7 +9,7 @@ import org.rekotlin.StateType
|
|||
|
||||
data class DisclaimerState(
|
||||
val disclaimer: Disclaimer = DummyDisclaimer(),
|
||||
val showedFromScreen: AppScreen = AppScreen.Home,
|
||||
val showedFrom: DisclaimerSource = DisclaimerSource.Home,
|
||||
val callback: DisclaimerCallback? = null,
|
||||
val progressState: ProgressState? = null,
|
||||
) : StateType
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.webkit.WebView
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
|
||||
import com.tangem.core.ui.extensions.setStatusBarColor
|
||||
import com.tangem.tap.common.entities.ProgressState
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
|
|
@ -18,6 +18,7 @@ import com.tangem.tap.features.BaseFragment
|
|||
import com.tangem.tap.features.addBackPressHandler
|
||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -76,17 +77,14 @@ class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubs
|
|||
|
||||
override fun configureTransitions() {
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
when (store.state.disclaimerState.showedFromScreen) {
|
||||
AppScreen.Home -> {
|
||||
when (store.state.disclaimerState.showedFrom) {
|
||||
DisclaimerSource.Home -> {
|
||||
enterTransition = inflater.inflateTransition(android.R.transition.slide_bottom)
|
||||
exitTransition = inflater.inflateTransition(android.R.transition.slide_top)
|
||||
}
|
||||
AppScreen.Details -> {
|
||||
DisclaimerSource.Details -> {
|
||||
super.configureTransitions()
|
||||
}
|
||||
else -> {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,15 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.core.ui.UiDependencies
|
||||
import com.tangem.core.ui.components.SystemBarsEffect
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.domain.tokens.TokensAction
|
||||
import com.tangem.tap.common.analytics.events.IntroductionProcess
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
|
|
@ -86,7 +87,7 @@ class HomeFragment : ComposeFragment(), StoreSubscriber<HomeState> {
|
|||
},
|
||||
onSearchTokensClick = {
|
||||
Analytics.send(IntroductionProcess.ButtonTokensList())
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.ManageTokens))
|
||||
store.dispatchNavigationAction { push(AppRoute.ManageTokens) }
|
||||
store.dispatch(TokensAction.SetArgs.ReadAccess)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@ import com.tangem.common.doOnFailure
|
|||
import com.tangem.common.doOnResult
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
|
|
@ -119,7 +118,7 @@ private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch {
|
|||
scope.launch { store.onUserWalletSelected(userWallet = userWallet) }
|
||||
}
|
||||
.doOnResult {
|
||||
navigateTo(AppScreen.Wallet)
|
||||
navigateTo(AppRoute.Wallet)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,8 +142,8 @@ private fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse) {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun navigateTo(appScreen: AppScreen) {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(appScreen))
|
||||
private suspend fun navigateTo(route: AppRoute) {
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
delay(HIDE_PROGRESS_DELAY)
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress = false))
|
||||
}
|
||||
|
|
@ -3,11 +3,11 @@ package com.tangem.tap.features.main
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.ReduxNavController
|
||||
|
||||
import com.tangem.domain.appcurrency.FetchAppCurrenciesUseCase
|
||||
import com.tangem.domain.balancehiding.BalanceHidingSettings
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
|
|
@ -36,7 +36,7 @@ import javax.inject.Inject
|
|||
internal class MainViewModel @Inject constructor(
|
||||
private val updateBalanceHidingSettingsUseCase: UpdateBalanceHidingSettingsUseCase,
|
||||
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
||||
private val reduxNavController: ReduxNavController,
|
||||
private val router: AppRouter,
|
||||
private val fetchAppCurrenciesUseCase: FetchAppCurrenciesUseCase,
|
||||
private val deleteDeprecatedLogsUseCase: DeleteDeprecatedLogsUseCase,
|
||||
private val incrementAppLaunchCounterUseCase: IncrementAppLaunchCounterUseCase,
|
||||
|
|
@ -152,7 +152,7 @@ internal class MainViewModel @Inject constructor(
|
|||
if (state.value.modalNotification?.isShow != true && !it.isUpdateFromToast) {
|
||||
listenToFlipsUseCase.changeUpdateEnabled(false)
|
||||
stateHolder.updateWithHiddenBalancesNotification()
|
||||
reduxNavController.navigate(NavigationAction.NavigateTo(AppScreen.ModalNotification))
|
||||
router.push(AppRoute.ModalNotification)
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package com.tangem.tap.features.onboarding
|
|||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
|
|
@ -56,18 +56,18 @@ object OnboardingHelper {
|
|||
}
|
||||
}
|
||||
|
||||
fun whereToNavigate(scanResponse: ScanResponse): AppScreen {
|
||||
fun whereToNavigate(scanResponse: ScanResponse): AppRoute {
|
||||
return when (val type = scanResponse.productType) {
|
||||
ProductType.Note -> AppScreen.OnboardingNote
|
||||
ProductType.Note -> AppRoute.OnboardingNote
|
||||
ProductType.Wallet,
|
||||
ProductType.Wallet2,
|
||||
ProductType.Ring,
|
||||
-> if (scanResponse.card.settings.isBackupAllowed) {
|
||||
AppScreen.OnboardingWallet
|
||||
AppRoute.OnboardingWallet()
|
||||
} else {
|
||||
AppScreen.OnboardingOther
|
||||
AppRoute.OnboardingOther
|
||||
}
|
||||
ProductType.Twins -> AppScreen.OnboardingTwins
|
||||
ProductType.Twins -> AppRoute.OnboardingTwins
|
||||
ProductType.Start2Coin,
|
||||
ProductType.Visa,
|
||||
-> throw UnsupportedOperationException("Onboarding for ${type.name} cards is not supported")
|
||||
|
|
@ -111,14 +111,14 @@ object OnboardingHelper {
|
|||
backupCardsIds = backupCardsIds?.toSet(),
|
||||
),
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { push(AppRoute.Wallet) }
|
||||
delay(timeMillis = 1_800)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.SaveWallet))
|
||||
store.dispatchNavigationAction { push(AppRoute.SaveWallet) }
|
||||
}
|
||||
// If device has no biometry and save wallet screen has been shown, then go through old scenario
|
||||
else -> {
|
||||
proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { push(AppRoute.Wallet) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package com.tangem.tap.features.onboarding.products.note.redux
|
|||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
|
|
@ -204,7 +205,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
|
|||
OnboardingDialog.InterruptOnboarding(
|
||||
onOk = {
|
||||
OnboardingHelper.onInterrupted()
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ package com.tangem.tap.features.onboarding.products.twins.redux
|
|||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
|
|
@ -39,6 +40,7 @@ import kotlinx.coroutines.runBlocking
|
|||
import org.rekotlin.Action
|
||||
import org.rekotlin.DispatchFunction
|
||||
import org.rekotlin.Middleware
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
object TwinCardsMiddleware {
|
||||
val handler = twinsWalletMiddleware
|
||||
|
|
@ -328,7 +330,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
if (walletsRepository.shouldSaveUserWalletsSync()) {
|
||||
OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse)
|
||||
} else {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Home>() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -352,7 +354,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
store.dispatch(TwinCardsAction.CardsManager.Release)
|
||||
|
||||
action.shouldResetTwinCardsWidget(shouldReturnCardBack) {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(getPopBackScreen()))
|
||||
store.dispatchNavigationAction { popTo(routeClass = getPopBackScreen()) }
|
||||
}
|
||||
}
|
||||
store.dispatchDialogShow(OnboardingDialog.InterruptOnboarding(onOkCallback))
|
||||
|
|
@ -362,18 +364,19 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun getPopBackScreen(): AppScreen {
|
||||
private fun getPopBackScreen(): KClass<out AppRoute> {
|
||||
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||
|
||||
return if (userWalletsListManager.hasUserWallets) {
|
||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
||||
.fold(onSuccess = { true }, onFailure = { false })
|
||||
|
||||
if (isLocked) {
|
||||
AppScreen.Welcome
|
||||
AppRoute.Welcome::class
|
||||
} else {
|
||||
AppScreen.Wallet
|
||||
AppRoute.Wallet::class
|
||||
}
|
||||
} else {
|
||||
AppScreen.Home
|
||||
AppRoute.Home::class
|
||||
}
|
||||
}
|
||||
|
|
@ -7,16 +7,16 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.extensions.ifNotNull
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.models.Artwork
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.models.Artwork
|
||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator
|
||||
|
|
@ -25,10 +25,7 @@ import com.tangem.operations.backup.BackupService
|
|||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
|
||||
|
|
@ -164,7 +161,7 @@ private fun handleWalletAction(action: Action) {
|
|||
store.dispatch(GlobalAction.Onboarding.Stop)
|
||||
|
||||
if (scanResponse == null) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
store.dispatch(HomeAction.ReadCard(scope = action.scope))
|
||||
} else {
|
||||
val backupState = store.state.onboardingWalletState.backupState
|
||||
|
|
@ -529,7 +526,8 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
addedBackupCardsCount = backupService.addedBackupCardsCount,
|
||||
),
|
||||
)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
||||
|
||||
store.dispatchNavigationAction { push(AppRoute.OnboardingWallet()) }
|
||||
}
|
||||
is BackupAction.SkipBackup -> {
|
||||
Analytics.send(Onboarding.Backup.Skipped())
|
||||
|
|
@ -614,7 +612,7 @@ private fun handleOnBackPressed(state: OnboardingWalletState) {
|
|||
}
|
||||
BackupStep.Finished -> {
|
||||
OnboardingHelper.onInterrupted()
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -625,7 +623,7 @@ private fun showInterruptOnboardingDialog() {
|
|||
onOk = {
|
||||
OnboardingHelper.onInterrupted()
|
||||
store.dispatch(BackupAction.DiscardBackup)
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ import com.google.android.material.tabs.TabLayoutMediator
|
|||
import com.tangem.common.CardIdFormatter
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.CardIdDisplayFormat
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.ui.extensions.setStatusBarColor
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||
import com.tangem.feature.onboarding.navigation.OnboardingRouter
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseMediator
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseRouter
|
||||
|
|
@ -66,7 +66,7 @@ class OnboardingWalletFragment :
|
|||
|
||||
internal val bindingSeedPhrase: LayoutOnboardingSeedPhraseBinding by lazy { binding.onboardingSeedPhraseContainer }
|
||||
|
||||
private val canSkipBackup by lazy { arguments?.getBoolean(OnboardingRouter.CAN_SKIP_BACKUP) ?: true }
|
||||
private val canSkipBackup by lazy { arguments?.getBoolean(AppRoute.OnboardingWallet.CAN_SKIP_BACKUP_KEY) ?: true }
|
||||
|
||||
private lateinit var seedPhraseStateHandler: OnboardingSeedPhraseStateHandler
|
||||
|
||||
|
|
|
|||
|
|
@ -3,26 +3,22 @@ package com.tangem.tap.features.saveWallet.redux
|
|||
import com.tangem.common.*
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
import org.rekotlin.Store
|
||||
import timber.log.Timber
|
||||
|
||||
internal class SaveWalletMiddleware {
|
||||
|
|
@ -80,7 +76,7 @@ internal class SaveWalletMiddleware {
|
|||
Timber.e(error, "Unable to save user wallet")
|
||||
}
|
||||
.doOnSuccess { mainScope.launch { store.onUserWalletSelected(userWallet) } }
|
||||
.doOnResult { store.navigateToWallet() }
|
||||
.doOnResult { navigateToWallet() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +126,7 @@ internal class SaveWalletMiddleware {
|
|||
)
|
||||
|
||||
store.dispatchWithMain(SaveWalletAction.AllowToUseBiometrics.Success)
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
}
|
||||
|
||||
private fun dismiss(state: SaveWalletState) {
|
||||
|
|
@ -159,13 +155,9 @@ internal class SaveWalletMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun Store<AppState>.navigateToWallet() {
|
||||
dispatchWithMain(
|
||||
if (store.state.navigationState.backStack.contains(AppScreen.Wallet)) {
|
||||
NavigationAction.PopBackTo(AppScreen.Wallet)
|
||||
} else {
|
||||
NavigationAction.NavigateTo(AppScreen.Wallet)
|
||||
},
|
||||
)
|
||||
private fun navigateToWallet() {
|
||||
store.dispatchNavigationAction {
|
||||
replaceAll(AppRoute.Wallet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@ import com.tangem.blockchain.common.transaction.Fee
|
|||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.blockchainsdk.utils.minimalAmount
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.demo.DemoTransactionSender
|
||||
|
|
@ -270,7 +270,7 @@ private fun sendTransaction(
|
|||
),
|
||||
)
|
||||
Analytics.sendSelectedCurrencyEvent(mainCurrencyType)
|
||||
dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
}
|
||||
}
|
||||
is SimpleResult.Failure -> {
|
||||
|
|
@ -326,7 +326,7 @@ private fun sendTransaction(
|
|||
AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_done,
|
||||
messageId = R.string.alert_demo_feature_disabled,
|
||||
onOk = { dispatch(NavigationAction.PopBackTo()) },
|
||||
onOk = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.text.method.DigitsKeyListener
|
|||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.postDelayed
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.fragment.app.viewModels
|
||||
|
|
@ -20,19 +19,18 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.tangem.Message
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.sdk.extensions.hideSoftKeyboard
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.analytics.events.Token
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.getFromClipboard
|
||||
import com.tangem.tap.common.extensions.setOnImeActionListener
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
|
|
@ -162,14 +160,9 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
imvQrCode.setOnClickListener {
|
||||
Analytics.send(Token.Send.ButtonQRCode())
|
||||
|
||||
store.dispatchOnMain(
|
||||
NavigationAction.NavigateTo(
|
||||
screen = AppScreen.QrScanning,
|
||||
bundle = bundleOf(
|
||||
QrScanningRouter.SOURCE_KEY to SourceType.SEND,
|
||||
),
|
||||
),
|
||||
)
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.QrScanning(source = SourceType.SEND))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +363,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
override fun handleOnBackPressed() {
|
||||
val externalTransactionData = store.state.sendState.externalTransactionData
|
||||
if (externalTransactionData == null) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
} else {
|
||||
store.dispatch(TradeCryptoAction.FinishSelling(externalTransactionData.transactionId))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.features.send.ui
|
|||
|
||||
import androidx.lifecycle.*
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||
|
|
@ -12,7 +13,6 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.tap.common.analytics.events.Token
|
||||
import com.tangem.tap.di.DelayedWork
|
||||
import com.tangem.tap.features.send.redux.AddressActionUi
|
||||
|
|
@ -52,7 +52,7 @@ internal class SendViewModel @Inject constructor(
|
|||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private val cryptoCurrency: CryptoCurrency? = savedStateHandle[SendRouter.CRYPTO_CURRENCY_KEY]
|
||||
private val cryptoCurrency: CryptoCurrency? = savedStateHandle[AppRoute.Send.CRYPTO_CURRENCY_KEY]
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
getBalanceHidingSettingsUseCase()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.tap.features.tokens.impl.presentation.router
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchNotification
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -18,11 +20,11 @@ import com.tangem.wallet.R
|
|||
internal class DefaultTokensListRouter : TokensListRouter {
|
||||
|
||||
override fun popBackStack() {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
}
|
||||
|
||||
override fun openAddCustomTokenScreen() {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddCustomToken))
|
||||
store.dispatchNavigationAction { push(AppRoute.AddCustomToken) }
|
||||
}
|
||||
|
||||
override fun showAddressCopiedNotification() {
|
||||
|
|
@ -54,7 +56,7 @@ internal class DefaultTokensListRouter : TokensListRouter {
|
|||
val alert = AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_error,
|
||||
messageId = R.string.common_unknown_error,
|
||||
onOk = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
onOk = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||
)
|
||||
store.dispatchDialogShow(alert)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.tangem.tap.features.tokens.impl.presentation.viewmodels
|
|||
import arrow.core.Either
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
|
|
@ -16,7 +16,7 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -126,7 +126,7 @@ internal class TokensListMigration(
|
|||
val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty()
|
||||
if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) {
|
||||
store.dispatchDebugErrorNotification(message = "Nothing to save")
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import androidx.lifecycle.viewModelScope
|
|||
import androidx.paging.*
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.core.ui.extensions.getGreyedOutIconRes
|
||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
||||
|
|
@ -26,7 +26,7 @@ import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
|||
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.TokenWithBlockchain
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
|
||||
import com.tangem.tap.common.extensions.getNetworkName
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.SupportBlockchainType
|
||||
|
|
@ -326,7 +326,7 @@ internal class TokensListViewModel @Inject constructor(
|
|||
)
|
||||
|
||||
uiState = state.copy(isSavingInProgress = false)
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
package com.tangem.tap.features.wallet.redux.middlewares
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.analytics.events.Token
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
import com.tangem.tap.common.extensions.*
|
||||
|
|
@ -150,7 +148,7 @@ object TradeCryptoMiddleware {
|
|||
}
|
||||
|
||||
private fun openReceiptUrl(transactionId: String) {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
||||
store.dispatchNavigationAction(AppRouter::pop)
|
||||
store.state.globalState.exchangeManager.getSellCryptoReceiptUrl(
|
||||
action = CurrencyExchangeManager.Action.Sell,
|
||||
transactionId = transactionId,
|
||||
|
|
@ -158,11 +156,7 @@ object TradeCryptoMiddleware {
|
|||
}
|
||||
|
||||
private fun openSwap(currency: CryptoCurrency) {
|
||||
val bundle = bundleOf(
|
||||
SwapFragment.CURRENCY_BUNDLE_KEY to currency,
|
||||
)
|
||||
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Swap, bundle = bundle))
|
||||
store.dispatchNavigationAction { push(AppRoute.Swap(currency = currency)) }
|
||||
}
|
||||
|
||||
private fun handleSendToken(action: TradeCryptoAction.SendToken) {
|
||||
|
|
@ -214,11 +208,12 @@ object TradeCryptoMiddleware {
|
|||
)
|
||||
}
|
||||
|
||||
val bundle = bundleOf(
|
||||
SendRouter.CRYPTO_CURRENCY_KEY to currency,
|
||||
SendRouter.USER_WALLET_ID_KEY to action.userWallet.walletId.stringValue,
|
||||
val route = AppRoute.Send(
|
||||
currency = currency,
|
||||
userWalletId = action.userWallet.walletId,
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
|
||||
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,17 +280,17 @@ object TradeCryptoMiddleware {
|
|||
)
|
||||
}
|
||||
|
||||
val bundle = bundleOf(
|
||||
SendRouter.CRYPTO_CURRENCY_KEY to currency,
|
||||
SendRouter.USER_WALLET_ID_KEY to action.userWallet.walletId.stringValue,
|
||||
val route = AppRoute.Send(
|
||||
currency = currency,
|
||||
userWalletId = action.userWallet.walletId,
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNewSendToken(action: TradeCryptoAction.SendToken) {
|
||||
handleNewSend(
|
||||
userWalletId = action.userWallet.walletId.stringValue,
|
||||
userWalletId = action.userWallet.walletId,
|
||||
txInfo = action.transactionInfo,
|
||||
currency = action.tokenCurrency,
|
||||
)
|
||||
|
|
@ -303,25 +298,26 @@ object TradeCryptoMiddleware {
|
|||
|
||||
private fun handleNewSendCoin(action: TradeCryptoAction.SendCoin) {
|
||||
handleNewSend(
|
||||
userWalletId = action.userWallet.walletId.stringValue,
|
||||
userWalletId = action.userWallet.walletId,
|
||||
txInfo = action.transactionInfo,
|
||||
currency = action.coinStatus.currency,
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleNewSend(
|
||||
userWalletId: String,
|
||||
userWalletId: UserWalletId,
|
||||
txInfo: TradeCryptoAction.TransactionInfo?,
|
||||
currency: CryptoCurrency,
|
||||
) {
|
||||
val bundle = bundleOf(
|
||||
SendRouter.CRYPTO_CURRENCY_KEY to currency,
|
||||
SendRouter.USER_WALLET_ID_KEY to userWalletId,
|
||||
SendRouter.TRANSACTION_ID_KEY to txInfo?.transactionId,
|
||||
SendRouter.DESTINATION_ADDRESS_KEY to txInfo?.destinationAddress,
|
||||
SendRouter.AMOUNT_KEY to txInfo?.amount,
|
||||
SendRouter.TAG_KEY to txInfo?.tag,
|
||||
val route = AppRoute.Send(
|
||||
currency = currency,
|
||||
userWalletId = userWalletId,
|
||||
transactionId = txInfo?.transactionId,
|
||||
destinationAddress = txInfo?.destinationAddress,
|
||||
amount = txInfo?.amount,
|
||||
tag = txInfo?.tag,
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
|
||||
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,12 @@ import com.tangem.common.doOnFailure
|
|||
import com.tangem.common.doOnResult
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.flatMap
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.utils.popTo
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
|
|
@ -98,7 +99,7 @@ internal class WelcomeMiddleware {
|
|||
signInType = Basic.SignedIn.SignInType.Biometric,
|
||||
)
|
||||
|
||||
store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { push(AppRoute.Wallet) }
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Success)
|
||||
store.onUserWalletSelected(userWallet = selectedUserWallet)
|
||||
|
||||
|
|
@ -130,7 +131,7 @@ internal class WelcomeMiddleware {
|
|||
.doOnSuccess {
|
||||
sendSignedInAnalyticsEvent(scanResponse = scanResponse, signInType = Basic.SignedIn.SignInType.Card)
|
||||
|
||||
store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchNavigationAction { push(AppRoute.Wallet) }
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success)
|
||||
store.onUserWalletSelected(userWallet = userWallet)
|
||||
|
||||
|
|
@ -170,7 +171,7 @@ internal class WelcomeMiddleware {
|
|||
}
|
||||
.doOnResult {
|
||||
store.dispatchWithMain(WelcomeAction.CloseError)
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
store.dispatchNavigationAction { popTo<AppRoute.Home>() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,8 +88,4 @@ internal class WelcomeFragment : ComposeFragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val INITIAL_INTENT_KEY = "intent"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
package com.tangem.tap.features.welcome.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.*
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.bundle.unbundle
|
||||
import com.tangem.common.routing.entity.SerializableIntent
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.tap.common.analytics.events.SignIn
|
||||
|
|
@ -26,7 +29,8 @@ internal class WelcomeViewModel @Inject constructor(
|
|||
StoreSubscriber<WelcomeState>,
|
||||
DefaultLifecycleObserver {
|
||||
|
||||
private val initialIntent: Intent? = savedStateHandle[WelcomeFragment.INITIAL_INTENT_KEY]
|
||||
private val initialIntent: SerializableIntent? = savedStateHandle.get<Bundle>(AppRoute.Welcome.INITIAL_INTENT_KEY)
|
||||
?.let { it.unbundle(SerializableIntent.serializer()) }
|
||||
|
||||
private val stateInternal = MutableStateFlow(WelcomeScreenState())
|
||||
val state: StateFlow<WelcomeScreenState> = stateInternal
|
||||
|
|
@ -38,7 +42,7 @@ internal class WelcomeViewModel @Inject constructor(
|
|||
initGlobalState()
|
||||
|
||||
val welcomeAction = if (initialIntent != null) {
|
||||
WelcomeAction.ProceedWithIntent(initialIntent)
|
||||
WelcomeAction.ProceedWithIntent(initialIntent.toIntent())
|
||||
} else {
|
||||
WelcomeAction.ProceedWithBiometrics()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
package com.tangem.tap.proxy
|
||||
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.ReduxNavController
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -23,7 +19,7 @@ import javax.inject.Inject
|
|||
* Holds objects from old modules, that missing in DI graph.
|
||||
* Object sets manually to use in new modules and [AppStateHolder] proxies its to DI.
|
||||
*/
|
||||
class AppStateHolder @Inject constructor() : ReduxNavController, ReduxStateHolder {
|
||||
class AppStateHolder @Inject constructor() : ReduxStateHolder {
|
||||
|
||||
@Deprecated("Use scan response from selected user wallet")
|
||||
var scanResponse: ScanResponse? = null
|
||||
|
|
@ -35,16 +31,6 @@ class AppStateHolder @Inject constructor() : ReduxNavController, ReduxStateHolde
|
|||
return scanResponse?.card
|
||||
}
|
||||
|
||||
override fun navigate(action: NavigationAction) {
|
||||
mainStore?.dispatchOnMain(action)
|
||||
}
|
||||
|
||||
override fun getBackStack(): List<AppScreen> = mainStore?.state?.navigationState?.backStack.orEmpty()
|
||||
|
||||
override fun popBackStack(screen: AppScreen?) {
|
||||
mainStore?.dispatchOnMain(NavigationAction.PopBackTo(screen))
|
||||
}
|
||||
|
||||
override fun dispatch(action: Action) {
|
||||
mainStore?.dispatch(action)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.proxy.redux
|
|||
|
||||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.navigation.email.EmailSender
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
|
|
@ -26,7 +27,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
|||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.features.details.DetailsEntryPoint
|
||||
import com.tangem.features.details.DetailsFeatureToggles
|
||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||
import com.tangem.features.managetokens.navigation.ManageTokensUi
|
||||
|
|
@ -81,8 +81,8 @@ data class DaggerGraphState(
|
|||
val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase? = null,
|
||||
val assetLoader: AssetLoader? = null,
|
||||
val detailsFeatureToggles: DetailsFeatureToggles? = null,
|
||||
val detailsEntryPoint: DetailsEntryPoint? = null,
|
||||
val stakingRouter: StakingRouter? = null,
|
||||
val urlOpener: UrlOpener? = null,
|
||||
val shareManager: ShareManager? = null,
|
||||
val appRouter: AppRouter? = null,
|
||||
) : StateType
|
||||
61
app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt
Normal file
61
app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.tap.routing
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal class ProxyAppRouter(
|
||||
private val config: AppRouterConfig,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : AppRouter {
|
||||
|
||||
private val routerScope: CoroutineScope
|
||||
get() = requireNotNull(config.routerScope) {
|
||||
"Router scope is not set in config"
|
||||
}
|
||||
|
||||
private val innerRouter: Router
|
||||
get() = requireNotNull(config.componentRouter) {
|
||||
"Inner router is not set in config"
|
||||
}
|
||||
|
||||
override val stack: List<AppRoute>
|
||||
get() = requireNotNull(config.stack) {
|
||||
"Stack is not set in config"
|
||||
}
|
||||
|
||||
override fun push(route: AppRoute, onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
routerScope.launch(dispatchers.mainImmediate) {
|
||||
innerRouter.push(route, onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
override fun replaceAll(vararg routes: AppRoute, onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
routerScope.launch(dispatchers.mainImmediate) {
|
||||
innerRouter.replaceAll(*routes, onComplete = onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
override fun pop(onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
routerScope.launch(dispatchers.mainImmediate) {
|
||||
innerRouter.pop(onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
override fun popTo(route: AppRoute, onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
routerScope.launch(dispatchers.mainImmediate) {
|
||||
innerRouter.popTo(route, onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
override fun popTo(routeClass: KClass<out AppRoute>, onComplete: (isSuccess: Boolean) -> Unit) {
|
||||
routerScope.launch(dispatchers.mainImmediate) {
|
||||
innerRouter.popTo(routeClass, onComplete)
|
||||
}
|
||||
}
|
||||
}
|
||||
33
app/src/main/java/com/tangem/tap/routing/RoutingComponent.kt
Normal file
33
app/src/main/java/com/tangem/tap/routing/RoutingComponent.kt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.tap.routing
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.utils.Provider
|
||||
|
||||
internal interface RoutingComponent {
|
||||
|
||||
val router: Router
|
||||
|
||||
val stack: Value<ChildStack<AppRoute, Child>>
|
||||
|
||||
sealed class Child {
|
||||
|
||||
data object Initial : Child()
|
||||
|
||||
data class LegacyFragment(
|
||||
val name: String,
|
||||
val fragmentProvider: Provider<Fragment>,
|
||||
) : Child()
|
||||
|
||||
data class LegacyIntent(val intent: Intent) : Child()
|
||||
}
|
||||
|
||||
interface Factory {
|
||||
fun create(context: AppComponentContext): RoutingComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.routing.configurator
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
internal interface AppRouterConfig {
|
||||
|
||||
var routerScope: CoroutineScope?
|
||||
var componentRouter: Router?
|
||||
var stack: List<AppRoute>?
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.routing.configurator
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
internal class MutableAppRouterConfig : AppRouterConfig {
|
||||
|
||||
override var routerScope: CoroutineScope? = null
|
||||
override var componentRouter: Router? = null
|
||||
override var stack: List<AppRoute>? = null
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.tangem.tap.routing.impl
|
||||
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.arkivanov.essenty.backhandler.BackCallback
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.navigation.getOrCreateTyped
|
||||
import com.tangem.tap.routing.RoutingComponent
|
||||
import com.tangem.tap.routing.RoutingComponent.Child
|
||||
import com.tangem.tap.routing.utils.ChildFactory
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
private val childFactory: ChildFactory,
|
||||
) : RoutingComponent, AppComponentContext by context {
|
||||
|
||||
private val backCallback = BackCallback(priority = Int.MIN_VALUE, onBack = router::pop)
|
||||
|
||||
override val stack: Value<ChildStack<AppRoute, Child>> = childStack(
|
||||
source = navigationProvider.getOrCreateTyped(),
|
||||
serializer = AppRoute.serializer(),
|
||||
initialConfiguration = getInitialRoute(),
|
||||
handleBackButton = false,
|
||||
childFactory = ::child,
|
||||
)
|
||||
|
||||
init {
|
||||
backHandler.register(backCallback)
|
||||
}
|
||||
|
||||
private fun getInitialRoute(): AppRoute = AppRoute.Initial
|
||||
|
||||
private fun child(route: AppRoute, context: ComponentContext): Child {
|
||||
return childFactory.createChild(route, { childByContext(context) })
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : RoutingComponent.Factory {
|
||||
override fun create(context: AppComponentContext): DefaultRoutingComponent
|
||||
}
|
||||
}
|
||||
164
app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
Normal file
164
app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
package com.tangem.tap.routing.utils
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.feature.referral.ReferralFragment
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.features.details.DetailsFeatureToggles
|
||||
import com.tangem.features.details.component.DetailsComponent
|
||||
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
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.AddCustomTokenFragment
|
||||
import com.tangem.tap.features.details.ui.appcurrency.AppCurrencySelectorFragment
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.coderecovery.AccessCodeRecoveryFragment
|
||||
import com.tangem.tap.features.details.ui.details.DetailsFragment
|
||||
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.walletconnect.WalletConnectFragment
|
||||
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
|
||||
import com.tangem.tap.features.home.HomeFragment
|
||||
import com.tangem.tap.features.main.ui.ModalNotificationBottomSheetFragment
|
||||
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.twins.ui.OnboardingTwinsFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment
|
||||
import com.tangem.tap.features.tokens.impl.presentation.TokensListFragment
|
||||
import com.tangem.tap.features.welcome.ui.WelcomeFragment
|
||||
import com.tangem.tap.routing.RoutingComponent.Child
|
||||
import com.tangem.utils.Provider
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
import java.util.WeakHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
@ActivityScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class ChildFactory @Inject constructor(
|
||||
private val detailsComponentFactory: DetailsComponent.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 detailsFeatureToggles: DetailsFeatureToggles,
|
||||
) {
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
fun createChild(route: AppRoute, contextFactory: (route: AppRoute) -> AppComponentContext): Child {
|
||||
componentContexts[route] = contextFactory(route)
|
||||
|
||||
return when (route) {
|
||||
is AppRoute.Initial -> {
|
||||
Child.Initial
|
||||
}
|
||||
is AppRoute.AccessCodeRecovery -> {
|
||||
route.asFragmentChild(Provider { AccessCodeRecoveryFragment() })
|
||||
}
|
||||
is AppRoute.AddCustomToken -> {
|
||||
route.asFragmentChild(Provider { AddCustomTokenFragment() })
|
||||
}
|
||||
is AppRoute.AppCurrencySelector -> {
|
||||
route.asFragmentChild(Provider { AppCurrencySelectorFragment() })
|
||||
}
|
||||
is AppRoute.ModalNotification -> {
|
||||
route.asFragmentChild(Provider { ModalNotificationBottomSheetFragment() })
|
||||
}
|
||||
is AppRoute.SaveWallet -> {
|
||||
route.asFragmentChild(Provider { SaveWalletBottomSheetFragment() })
|
||||
}
|
||||
is AppRoute.Send -> {
|
||||
route.asFragmentChild(Provider { sendRouter.getEntryFragment() })
|
||||
}
|
||||
is AppRoute.AppSettings -> {
|
||||
route.asFragmentChild(Provider { AppSettingsFragment() })
|
||||
}
|
||||
is AppRoute.CardSettings -> {
|
||||
route.asFragmentChild(Provider { CardSettingsFragment() })
|
||||
}
|
||||
is AppRoute.Details -> {
|
||||
if (detailsFeatureToggles.isRedesignEnabled) {
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = DetailsComponent.Params(route.userWalletId),
|
||||
componentFactory = detailsComponentFactory,
|
||||
)
|
||||
} else {
|
||||
route.asFragmentChild(Provider { DetailsFragment() })
|
||||
}
|
||||
}
|
||||
is AppRoute.DetailsSecurity -> {
|
||||
route.asFragmentChild(Provider { SecurityModeFragment() })
|
||||
}
|
||||
is AppRoute.Disclaimer -> {
|
||||
route.asFragmentChild(Provider { DisclaimerFragment() })
|
||||
}
|
||||
is AppRoute.Home -> {
|
||||
route.asFragmentChild(Provider { HomeFragment() })
|
||||
}
|
||||
is AppRoute.ManageTokens -> {
|
||||
route.asFragmentChild(Provider { TokensListFragment() })
|
||||
}
|
||||
is AppRoute.OnboardingNote -> {
|
||||
route.asFragmentChild(Provider { OnboardingNoteFragment() })
|
||||
}
|
||||
is AppRoute.OnboardingOther -> {
|
||||
route.asFragmentChild(Provider { OnboardingOtherCardsFragment() })
|
||||
}
|
||||
is AppRoute.OnboardingTwins -> {
|
||||
route.asFragmentChild(Provider { OnboardingTwinsFragment() })
|
||||
}
|
||||
is AppRoute.OnboardingWallet -> {
|
||||
route.asFragmentChild(Provider { OnboardingWalletFragment() })
|
||||
}
|
||||
is AppRoute.QrScanning -> {
|
||||
route.asFragmentChild(Provider { qrScanningRouter.getEntryFragment() })
|
||||
}
|
||||
is AppRoute.ReferralProgram -> {
|
||||
route.asFragmentChild(Provider { ReferralFragment() })
|
||||
}
|
||||
is AppRoute.ResetToFactory -> {
|
||||
route.asFragmentChild(Provider { ResetCardFragment() })
|
||||
}
|
||||
is AppRoute.Swap -> {
|
||||
route.asFragmentChild(Provider { SwapFragment() })
|
||||
}
|
||||
is AppRoute.Wallet -> {
|
||||
route.asFragmentChild(Provider { walletRouter.getEntryFragment() })
|
||||
}
|
||||
is AppRoute.WalletConnectSessions -> {
|
||||
route.asFragmentChild(Provider { WalletConnectFragment() })
|
||||
}
|
||||
is AppRoute.CurrencyDetails -> {
|
||||
route.asFragmentChild(Provider { tokenDetailsRouter.getEntryFragment() })
|
||||
}
|
||||
is AppRoute.Welcome -> {
|
||||
route.asFragmentChild(Provider { WelcomeFragment() })
|
||||
}
|
||||
is AppRoute.TesterMenu -> {
|
||||
Child.LegacyIntent(testerRouter.getEntryIntent())
|
||||
}
|
||||
is AppRoute.Staking -> {
|
||||
route.asFragmentChild(Provider { stakingRouter.getEntryFragment() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun contextProvider(
|
||||
appRoute: AppRoute,
|
||||
contextFactory: (route: AppRoute) -> AppComponentContext,
|
||||
): Provider<AppComponentContext> = Provider {
|
||||
componentContexts.getOrPut(appRoute) { contextFactory(appRoute) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
val componentContexts = WeakHashMap<AppRoute, AppComponentContext>()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.tap.routing.utils
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.bundle.RouteBundleParams
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.ComposableContentComponent
|
||||
import com.tangem.tap.DecomposeFragment
|
||||
import com.tangem.tap.routing.RoutingComponent.Child
|
||||
import com.tangem.utils.Provider
|
||||
|
||||
internal fun AppRoute.asFragmentChild(fragmentProvider: Provider<Fragment>): Child {
|
||||
val provider = Provider {
|
||||
val bundle = (this as? RouteBundleParams)?.getBundle()
|
||||
|
||||
fragmentProvider().apply {
|
||||
arguments = bundle
|
||||
}
|
||||
}
|
||||
|
||||
return Child.LegacyFragment(path, provider)
|
||||
}
|
||||
|
||||
internal fun <C : ComposableContentComponent, P : Any, F : ComponentFactory<C, P>> AppRoute.asComponentChild(
|
||||
contextProvider: Provider<AppComponentContext>,
|
||||
params: P,
|
||||
componentFactory: F,
|
||||
): Child {
|
||||
val fragmentProvider = Provider {
|
||||
DecomposeFragment.newInstance(
|
||||
contextProvider = contextProvider,
|
||||
params = params,
|
||||
componentFactory = componentFactory,
|
||||
)
|
||||
}
|
||||
|
||||
return Child.LegacyFragment(path, fragmentProvider)
|
||||
}
|
||||
1
common/routing/.gitignore
vendored
Normal file
1
common/routing/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
26
common/routing/build.gradle.kts
Normal file
26
common/routing/build.gradle.kts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.common.routing"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/* Core */
|
||||
implementation(projects.core.decompose)
|
||||
|
||||
/* Domain */
|
||||
implementation(projects.domain.qrScanning.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.staking.models)
|
||||
|
||||
/* Libs - Other */
|
||||
api(deps.kotlin.serialization)
|
||||
implementation(deps.androidx.core.ktx)
|
||||
implementation(deps.timber)
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
package com.tangem.common.routing
|
||||
|
||||
import android.os.Bundle
|
||||
import com.tangem.common.routing.bundle.RouteBundleParams
|
||||
import com.tangem.common.routing.bundle.bundle
|
||||
import com.tangem.common.routing.entity.SerializableIntent
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.domain.staking.model.Yield
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
sealed class AppRoute(val path: String) : Route, RouteBundleParams {
|
||||
|
||||
override fun getBundle(): Bundle = bundle(serializer())
|
||||
|
||||
@Serializable
|
||||
data object Initial : AppRoute(path = "/initial")
|
||||
|
||||
@Serializable
|
||||
data object Home : AppRoute(path = "/home")
|
||||
|
||||
@Serializable
|
||||
data class Welcome(
|
||||
val intent: SerializableIntent? = null,
|
||||
) : AppRoute(path = "/welcome") {
|
||||
|
||||
companion object {
|
||||
const val INITIAL_INTENT_KEY = "intent"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Disclaimer(
|
||||
val isTosAccepted: Boolean,
|
||||
) : AppRoute(path = "/disclaimer${if (isTosAccepted) "/tos_accepted" else ""}") {
|
||||
|
||||
companion object {
|
||||
const val IS_TOS_ACCEPTED_KEY = "isTosAccepted"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object OnboardingNote : AppRoute(path = "/onboarding/note")
|
||||
|
||||
@Serializable
|
||||
data class OnboardingWallet(
|
||||
val canSkipBackup: Boolean = true,
|
||||
) : AppRoute(path = "/onboarding/wallet${if (canSkipBackup) "/skippable" else ""}") {
|
||||
|
||||
companion object {
|
||||
const val CAN_SKIP_BACKUP_KEY = "canSkipBackup"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object OnboardingTwins : AppRoute(path = "/onboarding/twins")
|
||||
|
||||
@Serializable
|
||||
data object OnboardingOther : AppRoute(path = "/onboarding/other")
|
||||
|
||||
@Serializable
|
||||
data object Wallet : AppRoute(path = "/wallet")
|
||||
|
||||
@Serializable
|
||||
data class CurrencyDetails(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
) : AppRoute(path = "/currency_details/${userWalletId.stringValue}/${currency.id.value}") {
|
||||
|
||||
companion object {
|
||||
const val USER_WALLET_ID_KEY = "userWalletId"
|
||||
const val CRYPTO_CURRENCY_KEY = "currency"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Send(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
val transactionId: String? = null,
|
||||
val amount: String? = null,
|
||||
val tag: String? = null,
|
||||
val destinationAddress: String? = null,
|
||||
) : AppRoute(
|
||||
path = "/send/${userWalletId.stringValue}/${currency.id.value}?" +
|
||||
"&$transactionId" +
|
||||
"&$amount" +
|
||||
"&$tag" +
|
||||
"&$destinationAddress",
|
||||
) {
|
||||
companion object {
|
||||
const val USER_WALLET_ID_KEY = "userWalletId"
|
||||
const val CRYPTO_CURRENCY_KEY = "currency"
|
||||
const val TRANSACTION_ID_KEY = "transactionId"
|
||||
const val AMOUNT_KEY = "amount"
|
||||
const val TAG_KEY = "tag"
|
||||
const val DESTINATION_ADDRESS_KEY = "destinationAddress"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Details(
|
||||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/details/${userWalletId.stringValue}")
|
||||
|
||||
@Serializable
|
||||
data object DetailsSecurity : AppRoute(path = "/details/security")
|
||||
|
||||
@Serializable
|
||||
data object CardSettings : AppRoute(path = "/card_settings")
|
||||
|
||||
@Serializable
|
||||
data object AppSettings : AppRoute(path = "/app_settings")
|
||||
|
||||
@Serializable
|
||||
data object ResetToFactory : AppRoute(path = "/reset_to_factory")
|
||||
|
||||
@Serializable
|
||||
data object AccessCodeRecovery : AppRoute(path = "/access_code_recovery")
|
||||
|
||||
@Serializable
|
||||
data object ManageTokens : AppRoute(path = "/manage_tokens")
|
||||
|
||||
@Serializable
|
||||
data object AddCustomToken : AppRoute(path = "/add_custom_token")
|
||||
|
||||
@Serializable
|
||||
data object WalletConnectSessions : AppRoute(path = "/wallet_connect_sessions")
|
||||
|
||||
@Serializable
|
||||
data class QrScanning(
|
||||
val source: SourceType,
|
||||
val networkName: String? = null,
|
||||
) : AppRoute(path = "/qr_scanning") {
|
||||
|
||||
companion object {
|
||||
const val SOURCE_KEY = "source"
|
||||
const val NETWORK_KEY = "networkName"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object ReferralProgram : AppRoute(path = "/referral_program")
|
||||
|
||||
@Serializable
|
||||
data class Swap(
|
||||
val currency: CryptoCurrency,
|
||||
) : AppRoute(path = "/swap") {
|
||||
|
||||
companion object {
|
||||
const val CURRENCY_BUNDLE_KEY = "currency"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object TesterMenu : AppRoute(path = "/tester_menu")
|
||||
|
||||
@Serializable
|
||||
data object SaveWallet : AppRoute(path = "/save_wallet")
|
||||
|
||||
@Serializable
|
||||
data object AppCurrencySelector : AppRoute(path = "/app_currency_selector")
|
||||
|
||||
@Serializable
|
||||
data object ModalNotification : AppRoute(path = "/modal_notification")
|
||||
|
||||
@Serializable
|
||||
data class Staking(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrencyId: CryptoCurrency.ID,
|
||||
val yield: Yield,
|
||||
) : AppRoute(path = "/staking/${userWalletId.stringValue}/${cryptoCurrencyId.value}/${yield.id}") {
|
||||
|
||||
companion object {
|
||||
const val USER_WALLET_ID_KEY = "userWalletId"
|
||||
const val CRYPTO_CURRENCY_ID_KEY = "cryptoCurrencyId"
|
||||
const val YIELD_KEY = "yield"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.tangem.common.routing
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Interface for a router in the application.
|
||||
* It provides methods for navigating through the application.
|
||||
*
|
||||
* Same as [com.tangem.core.decompose.navigation.Router] but without Decompose dependency.
|
||||
*
|
||||
* ***Must be removed after Decompose migration.***
|
||||
*/
|
||||
interface AppRouter {
|
||||
|
||||
/**
|
||||
* The current navigation stack.
|
||||
*/
|
||||
val stack: List<AppRoute>
|
||||
|
||||
/**
|
||||
* Pushes a new route to the navigation stack.
|
||||
*
|
||||
* @param route The route to push.
|
||||
* @param onComplete The callback to be invoked when the operation is complete.
|
||||
*/
|
||||
fun push(route: AppRoute, onComplete: (isSuccess: Boolean) -> Unit = {})
|
||||
|
||||
/**
|
||||
* Replaces ***all*** routes in the navigation stack with the specified [routes].
|
||||
*
|
||||
* @param routes The routes to replace the current stack with.
|
||||
* @param onComplete The callback to be invoked when the operation is complete.
|
||||
*/
|
||||
fun replaceAll(vararg routes: AppRoute, onComplete: (isSuccess: Boolean) -> Unit = {})
|
||||
|
||||
/**
|
||||
* Pops the top route from the navigation stack.
|
||||
*
|
||||
* @param onComplete The callback to be invoked when the operation is complete.
|
||||
*/
|
||||
fun pop(onComplete: (isSuccess: Boolean) -> Unit = {})
|
||||
|
||||
/**
|
||||
* Pops routes from the navigation stack until the specified [route] is found.
|
||||
*
|
||||
* @param route The route to pop to.
|
||||
* @param onComplete The callback to be invoked when the operation is complete.
|
||||
*/
|
||||
fun popTo(route: AppRoute, onComplete: (isSuccess: Boolean) -> Unit = {})
|
||||
|
||||
/**
|
||||
* Pops routes from the navigation stack until the ***first*** specified [routeClass] is found.
|
||||
*
|
||||
* @param routeClass The route class to pop to.
|
||||
* @param onComplete The callback to be invoked when the operation is complete.
|
||||
*/
|
||||
fun popTo(routeClass: KClass<out AppRoute>, onComplete: (isSuccess: Boolean) -> Unit = {})
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package com.tangem.common.routing.bundle
|
||||
|
||||
import android.os.Bundle
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.StructureKind
|
||||
import kotlinx.serialization.encoding.AbstractDecoder
|
||||
import kotlinx.serialization.encoding.CompositeDecoder
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
|
||||
@ExperimentalSerializationApi
|
||||
internal class BundleDecoder(
|
||||
private val bundle: Bundle,
|
||||
private val elementsCount: Int = -1,
|
||||
private val isInitializer: Boolean = true,
|
||||
override val serializersModule: SerializersModule,
|
||||
) : AbstractDecoder() {
|
||||
|
||||
private var index = -1
|
||||
private var elementKey: String? = null
|
||||
|
||||
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
|
||||
if (++index >= elementsCount) {
|
||||
return CompositeDecoder.DECODE_DONE
|
||||
}
|
||||
|
||||
elementKey = descriptor.getElementName(index)
|
||||
return index
|
||||
}
|
||||
|
||||
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
|
||||
val b = if (isInitializer) {
|
||||
bundle
|
||||
} else {
|
||||
requireNotNull(bundle.getBundle(elementKey)) {
|
||||
"Bundle is missing for key $elementKey while decoding"
|
||||
}
|
||||
}
|
||||
|
||||
val count = when (descriptor.kind) {
|
||||
StructureKind.MAP,
|
||||
StructureKind.LIST,
|
||||
-> b.getInt("\$size")
|
||||
else -> descriptor.elementsCount
|
||||
}
|
||||
|
||||
return BundleDecoder(
|
||||
bundle = b,
|
||||
elementsCount = count,
|
||||
isInitializer = false,
|
||||
serializersModule = serializersModule,
|
||||
)
|
||||
}
|
||||
|
||||
override fun endStructure(descriptor: SerialDescriptor) {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
override fun decodeBoolean(): Boolean {
|
||||
return bundle.getBoolean(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeByte(): Byte {
|
||||
return bundle.getByte(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeChar(): Char {
|
||||
return bundle.getChar(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeDouble(): Double {
|
||||
return bundle.getDouble(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int {
|
||||
return bundle.getInt(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeFloat(): Float {
|
||||
return bundle.getFloat(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeInt(): Int {
|
||||
return bundle.getInt(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeLong(): Long {
|
||||
return bundle.getLong(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeNotNullMark(): Boolean {
|
||||
return bundle.containsKey(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeNull(): Nothing? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun decodeShort(): Short {
|
||||
return bundle.getShort(elementKey)
|
||||
}
|
||||
|
||||
override fun decodeString(): String {
|
||||
return requireNotNull(bundle.getString(elementKey)) {
|
||||
"String is missing for key $elementKey while decoding"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.tangem.common.routing.bundle
|
||||
|
||||
import android.os.Bundle
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.StructureKind
|
||||
import kotlinx.serialization.encoding.AbstractEncoder
|
||||
import kotlinx.serialization.encoding.CompositeEncoder
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
|
||||
@ExperimentalSerializationApi
|
||||
internal class BundleEncoder(
|
||||
private val bundle: Bundle,
|
||||
private val parentBundle: Bundle? = null,
|
||||
private val keyInParent: String? = null,
|
||||
private val isInitializer: Boolean = true,
|
||||
override val serializersModule: SerializersModule,
|
||||
) : AbstractEncoder() {
|
||||
|
||||
private var elementKey: String? = null
|
||||
|
||||
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean {
|
||||
elementKey = descriptor.getElementName(index)
|
||||
return super.encodeElement(descriptor, index)
|
||||
}
|
||||
|
||||
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
|
||||
return if (isInitializer) {
|
||||
BundleEncoder(
|
||||
bundle = bundle,
|
||||
parentBundle = null,
|
||||
keyInParent = elementKey,
|
||||
isInitializer = false,
|
||||
serializersModule = serializersModule,
|
||||
)
|
||||
} else {
|
||||
BundleEncoder(
|
||||
bundle = Bundle(),
|
||||
parentBundle = bundle,
|
||||
keyInParent = elementKey,
|
||||
isInitializer = false,
|
||||
serializersModule = serializersModule,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun endStructure(descriptor: SerialDescriptor) {
|
||||
if (descriptor.kind in arrayOf(StructureKind.LIST, StructureKind.MAP)) {
|
||||
val size = elementKey?.toIntOrNull()?.let { it + 1 } ?: 0
|
||||
bundle.putInt("\$size", size)
|
||||
}
|
||||
|
||||
if (keyInParent.isNullOrBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
parentBundle?.putBundle(keyInParent, bundle)
|
||||
}
|
||||
|
||||
override fun encodeBoolean(value: Boolean) {
|
||||
bundle.putBoolean(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeByte(value: Byte) {
|
||||
bundle.putByte(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeChar(value: Char) {
|
||||
bundle.putChar(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeDouble(value: Double) {
|
||||
bundle.putDouble(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) {
|
||||
bundle.putInt(elementKey, index)
|
||||
}
|
||||
|
||||
override fun encodeFloat(value: Float) {
|
||||
bundle.putFloat(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeInt(value: Int) {
|
||||
bundle.putInt(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeLong(value: Long) {
|
||||
bundle.putLong(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeNull() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
override fun encodeShort(value: Short) {
|
||||
bundle.putShort(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeString(value: String) {
|
||||
bundle.putString(elementKey, value)
|
||||
}
|
||||
|
||||
override fun encodeNotNullMark() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.tangem.common.routing.bundle
|
||||
|
||||
import android.os.Bundle
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
import kotlinx.serialization.modules.EmptySerializersModule
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
|
||||
val defaultSerializersModule: SerializersModule = EmptySerializersModule()
|
||||
|
||||
/**
|
||||
* Deserialize this bundle into an object of type [T].
|
||||
*
|
||||
* @receiver [Bundle] to deserialize.
|
||||
* @param deserializer [DeserializationStrategy] of the [T] class.
|
||||
*
|
||||
* @return Object of type T deserialized from bundle.
|
||||
*/
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun <T> Bundle.unbundle(
|
||||
deserializer: DeserializationStrategy<T>,
|
||||
serializersModule: SerializersModule = defaultSerializersModule,
|
||||
): T {
|
||||
val decoder = BundleDecoder(
|
||||
bundle = this,
|
||||
elementsCount = -1,
|
||||
isInitializer = true,
|
||||
serializersModule = serializersModule,
|
||||
)
|
||||
|
||||
return deserializer.deserialize(decoder)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize [T] into a bundle.
|
||||
*
|
||||
* @receiver Object to serialize.
|
||||
* @param serializer [SerializationStrategy] of the [T] class.
|
||||
*
|
||||
* @return bundle serialized from value
|
||||
*/
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun <T> T.bundle(
|
||||
serializer: SerializationStrategy<T>,
|
||||
serializersModule: SerializersModule = defaultSerializersModule,
|
||||
): Bundle {
|
||||
val bundle = Bundle(serializer.descriptor.elementsCount)
|
||||
val encoder = BundleEncoder(
|
||||
bundle = bundle,
|
||||
parentBundle = null,
|
||||
keyInParent = null,
|
||||
isInitializer = true,
|
||||
serializersModule = serializersModule,
|
||||
)
|
||||
|
||||
serializer.serialize(encoder, value = this)
|
||||
|
||||
return bundle
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.common.routing.bundle
|
||||
|
||||
import android.os.Bundle
|
||||
|
||||
interface RouteBundleParams {
|
||||
|
||||
fun getBundle(): Bundle
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.common.routing.entity
|
||||
|
||||
import android.os.Bundle
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SerializableBundle(
|
||||
val map: Map<String, String>,
|
||||
) {
|
||||
|
||||
constructor(bundle: Bundle) : this(
|
||||
map = bundle.keySet().mapNotNull { key ->
|
||||
bundle.getString(key)?.let { key to it }
|
||||
}.toMap(),
|
||||
)
|
||||
|
||||
fun toBundle(): Bundle {
|
||||
return Bundle().apply {
|
||||
map.forEach { (key, value) ->
|
||||
putString(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.common.routing.entity
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SerializableIntent(
|
||||
val action: String?,
|
||||
val dataString: String?,
|
||||
val categories: Set<String>?,
|
||||
val type: String?,
|
||||
val packageValue: String?,
|
||||
val component: String?,
|
||||
val flags: Int,
|
||||
val extras: SerializableBundle?,
|
||||
) {
|
||||
|
||||
constructor(intent: Intent) : this(
|
||||
action = intent.action,
|
||||
dataString = intent.dataString,
|
||||
categories = intent.categories,
|
||||
type = intent.type,
|
||||
packageValue = intent.`package`,
|
||||
component = intent.component?.flattenToString(),
|
||||
flags = intent.flags,
|
||||
extras = intent.extras?.let(::SerializableBundle),
|
||||
)
|
||||
|
||||
fun toIntent(): Intent {
|
||||
val intent = Intent()
|
||||
|
||||
intent.action = action
|
||||
intent.setDataAndType(
|
||||
dataString?.let { Uri.parse(it) },
|
||||
type,
|
||||
)
|
||||
categories?.let { categories ->
|
||||
for (category in categories) {
|
||||
intent.addCategory(category)
|
||||
}
|
||||
}
|
||||
intent.`package` = packageValue
|
||||
intent.component = component?.let { ComponentName.unflattenFromString(it) }
|
||||
intent.flags = flags
|
||||
extras?.let { intent.putExtras(it.toBundle()) }
|
||||
|
||||
return intent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.common.routing.utils
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
|
||||
/**
|
||||
* Pops routes from the navigation stack until the specified route [R] is found.
|
||||
*
|
||||
* ***Must be removed after Decompose migration.***
|
||||
*
|
||||
* @param R The route to pop to.
|
||||
* @param onComplete The callback to be invoked when the operation is complete.
|
||||
*/
|
||||
inline fun <reified R : AppRoute> AppRouter.popTo(noinline onComplete: (isSuccess: Boolean) -> Unit = {}) {
|
||||
popTo(R::class, onComplete)
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.core.navigation
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.rekotlin.Action
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
sealed class NavigationAction : Action {
|
||||
|
||||
data class NavigateTo(
|
||||
val screen: AppScreen,
|
||||
val fragmentShareTransition: FragmentShareTransition? = null,
|
||||
val addToBackstack: Boolean = true,
|
||||
val bundle: Bundle? = null,
|
||||
) : NavigationAction()
|
||||
|
||||
data class PopBackTo(val screen: AppScreen? = null, val inclusive: Boolean = false) : NavigationAction()
|
||||
|
||||
data class OpenDocument(val url: Uri) : NavigationAction()
|
||||
|
||||
data class ActivityCreated(val activity: WeakReference<AppCompatActivity>) : NavigationAction()
|
||||
|
||||
data class ActivityDestroyed(val activity: WeakReference<AppCompatActivity>) : NavigationAction()
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.core.navigation
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.rekotlin.StateType
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
data class NavigationState(
|
||||
val backStack: List<AppScreen> = emptyList(),
|
||||
val activity: WeakReference<AppCompatActivity>? = null,
|
||||
) : StateType
|
||||
|
||||
enum class AppScreen(val isDialogFragment: Boolean = false) {
|
||||
Home,
|
||||
Disclaimer,
|
||||
OnboardingNote,
|
||||
OnboardingWallet,
|
||||
OnboardingTwins,
|
||||
OnboardingOther,
|
||||
Wallet,
|
||||
WalletDetails,
|
||||
Send(isDialogFragment = true),
|
||||
Details,
|
||||
DetailsSecurity,
|
||||
CardSettings,
|
||||
AppSettings,
|
||||
ResetToFactory,
|
||||
AccessCodeRecovery,
|
||||
ManageTokens,
|
||||
AddCustomToken,
|
||||
WalletConnectSessions,
|
||||
QrScanning,
|
||||
ReferralProgram,
|
||||
Swap,
|
||||
Welcome,
|
||||
SaveWallet(isDialogFragment = true),
|
||||
AppCurrencySelector,
|
||||
ModalNotification(isDialogFragment = true),
|
||||
Staking,
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package com.tangem.core.navigation
|
||||
|
||||
/**
|
||||
* Navigation controller that based on redux actions
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface ReduxNavController {
|
||||
|
||||
/** Navigate by [action] */
|
||||
fun navigate(action: NavigationAction)
|
||||
|
||||
fun popBackStack(screen: AppScreen? = null)
|
||||
|
||||
fun getBackStack(): List<AppScreen>
|
||||
}
|
||||
|
|
@ -1,18 +1,8 @@
|
|||
package com.tangem.core.navigation
|
||||
|
||||
import android.view.View
|
||||
import androidx.transition.TransitionSet
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class FragmentShareTransition(
|
||||
val shareElements: List<ShareElement>,
|
||||
val enterTransitionSet: TransitionSet,
|
||||
val exitTransitionSet: TransitionSet,
|
||||
)
|
||||
|
||||
/**
|
||||
* For ease of use, the name is used as transitionName\name into the FragmentTransaction.addSharedElement
|
||||
*/
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -7,4 +8,6 @@ dependencies {
|
|||
api(deps.kotlin.coroutines)
|
||||
api(deps.arrow.core)
|
||||
api(deps.arrow.fx)
|
||||
|
||||
implementation(deps.kotlin.serialization)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.domain.core.serialization
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal object BigDecimalSerializer : KSerializer<BigDecimal> {
|
||||
|
||||
override val descriptor = PrimitiveSerialDescriptor(serialName = "BigDecimal", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: BigDecimal) {
|
||||
encoder.encodeString(value.toString())
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): BigDecimal {
|
||||
return BigDecimal(decoder.decodeString())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.core.serialization
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.math.BigDecimal
|
||||
|
||||
typealias SerializedBigDecimal = @Serializable(with = BigDecimalSerializer::class) BigDecimal
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -10,10 +11,10 @@ android {
|
|||
|
||||
|
||||
dependencies {
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.arrow.core)
|
||||
implementation(deps.kotlin.serialization)
|
||||
api(projects.domain.staking.models)
|
||||
|
||||
api(projects.domain.core)
|
||||
implementation(deps.kotlin.serialization)
|
||||
|
||||
implementation(projects.domain.tokens.models)
|
||||
}
|
||||
1
domain/staking/models/.gitignore
vendored
Normal file
1
domain/staking/models/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
11
domain/staking/models/build.gradle.kts
Normal file
11
domain/staking/models/build.gradle.kts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.domain.core)
|
||||
|
||||
implementation(deps.kotlin.serialization)
|
||||
}
|
||||
|
|
@ -1,54 +1,64 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
import java.io.Serializable
|
||||
import java.math.BigDecimal
|
||||
import com.tangem.domain.core.serialization.SerializedBigDecimal
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Yield(
|
||||
val id: String,
|
||||
val token: Token,
|
||||
val tokens: List<Token>,
|
||||
val args: Args,
|
||||
val status: Status,
|
||||
val apy: BigDecimal,
|
||||
val apy: SerializedBigDecimal,
|
||||
val rewardRate: Double,
|
||||
val rewardType: RewardType,
|
||||
val metadata: Metadata,
|
||||
val validators: List<Validator>,
|
||||
val isAvailable: Boolean,
|
||||
) : Serializable {
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Status(
|
||||
val enter: Boolean,
|
||||
val exit: Boolean?,
|
||||
) : Serializable
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Args(
|
||||
val enter: Enter,
|
||||
val exit: Enter?,
|
||||
) : Serializable {
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Enter(
|
||||
val addresses: Addresses,
|
||||
val args: Map<String, AddressArgument>,
|
||||
) : Serializable {
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Addresses(
|
||||
val address: AddressArgument,
|
||||
val additionalAddresses: Map<String, AddressArgument>? = null,
|
||||
) : Serializable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Validator(
|
||||
val address: String,
|
||||
val status: String,
|
||||
val name: String,
|
||||
val image: String?,
|
||||
val website: String?,
|
||||
val apr: BigDecimal?,
|
||||
val apr: SerializedBigDecimal?,
|
||||
val commission: Double?,
|
||||
val stakedBalance: String?,
|
||||
val votingPower: Double?,
|
||||
val preferred: Boolean,
|
||||
) : Serializable
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Metadata(
|
||||
val name: String,
|
||||
val logoUri: String,
|
||||
|
|
@ -67,14 +77,17 @@ data class Yield(
|
|||
val supportsMultipleValidators: Boolean,
|
||||
val revshare: Enabled,
|
||||
val fee: Enabled,
|
||||
) : Serializable {
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Period(
|
||||
val days: Int,
|
||||
) : Serializable
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Enabled(
|
||||
val enabled: Boolean,
|
||||
) : Serializable
|
||||
)
|
||||
}
|
||||
|
||||
enum class RewardType {
|
||||
|
|
@ -84,6 +97,7 @@ data class Yield(
|
|||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Token(
|
||||
val name: String,
|
||||
val network: NetworkType,
|
||||
|
|
@ -93,7 +107,7 @@ data class Token(
|
|||
val coinGeckoId: String?,
|
||||
val logoURI: String?,
|
||||
val isPoints: Boolean?,
|
||||
) : Serializable {
|
||||
) {
|
||||
enum class NetworkType {
|
||||
AVALANCHE_C,
|
||||
AVALANCHE_ATOMIC,
|
||||
|
|
@ -165,9 +179,10 @@ data class Token(
|
|||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class AddressArgument(
|
||||
val required: Boolean,
|
||||
val network: String? = null,
|
||||
val minimum: Double? = null,
|
||||
val maximum: Double? = null,
|
||||
) : Serializable
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("kotlin-parcelize")
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(deps.tangem.blockchain) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a generic cryptocurrency.
|
||||
|
|
@ -14,8 +13,8 @@ import kotlinx.parcelize.Parcelize
|
|||
* @property iconUrl Optional URL of the cryptocurrency icon. `null` if not found.
|
||||
* @property isCustom Indicates whether the currency is a custom user-added currency or not.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class CryptoCurrency : Parcelable {
|
||||
@Serializable
|
||||
sealed class CryptoCurrency {
|
||||
|
||||
abstract val id: ID
|
||||
abstract val network: Network
|
||||
|
|
@ -28,6 +27,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
/**
|
||||
* Represents a native coin in the blockchain network.
|
||||
*/
|
||||
@Serializable
|
||||
data class Coin(
|
||||
override val id: ID,
|
||||
override val network: Network,
|
||||
|
|
@ -48,6 +48,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* @property contractAddress Address of the contract managing the token.
|
||||
*/
|
||||
@Serializable
|
||||
data class Token(
|
||||
override val id: ID,
|
||||
override val network: Network,
|
||||
|
|
@ -75,12 +76,12 @@ sealed class CryptoCurrency : Parcelable {
|
|||
* @property rawCurrencyId Represents not unique currency ID from the blockchain network. `null` if
|
||||
* its ID of the custom token.
|
||||
*/
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class ID(
|
||||
private val prefix: Prefix,
|
||||
private val body: Body,
|
||||
private val suffix: Suffix,
|
||||
) : Parcelable {
|
||||
) {
|
||||
|
||||
val value: String
|
||||
get() = buildString {
|
||||
|
|
@ -121,12 +122,13 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* The body can be either a raw network ID or a raw network ID with a network derivation path.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class Body : Parcelable {
|
||||
@Serializable
|
||||
sealed class Body {
|
||||
|
||||
/** The value of the body. */
|
||||
abstract val value: String
|
||||
|
||||
@Serializable
|
||||
/** Represents a raw network ID. */
|
||||
data class NetworkId(val rawId: String) : Body() {
|
||||
override val value: String get() = rawId
|
||||
|
|
@ -137,6 +139,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* Should be used for a cryptocurrencies with custom derivation path.
|
||||
* */
|
||||
@Serializable
|
||||
data class NetworkIdWithDerivationPath(
|
||||
val rawId: String,
|
||||
val derivationPath: String,
|
||||
|
|
@ -155,13 +158,14 @@ sealed class CryptoCurrency : Parcelable {
|
|||
*
|
||||
* The suffix can either be a raw ID or a contract address.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class Suffix : Parcelable {
|
||||
@Serializable
|
||||
sealed class Suffix {
|
||||
|
||||
/** The value of the suffix, which could be either a raw ID or a contract address. */
|
||||
abstract val value: String
|
||||
|
||||
/** Represents a raw ID suffix. */
|
||||
@Serializable
|
||||
data class RawID(val rawId: String, val contractAddress: String? = null) : Suffix() {
|
||||
override val value: String
|
||||
get() = buildString {
|
||||
|
|
@ -174,6 +178,7 @@ sealed class CryptoCurrency : Parcelable {
|
|||
}
|
||||
|
||||
/** Represents a contract address suffix. */
|
||||
@Serializable
|
||||
data class ContractAddress(val contractAddress: String) : Suffix() {
|
||||
override val value: String get() = contractAddress
|
||||
}
|
||||
|
|
@ -183,11 +188,11 @@ sealed class CryptoCurrency : Parcelable {
|
|||
return "ID(value='$value')"
|
||||
}
|
||||
|
||||
private companion object {
|
||||
companion object {
|
||||
// should use delimiters that could be used in URL not like path or query delimiters
|
||||
const val PREFIX_DELIMITER = '_'
|
||||
const val SUFFIX_DELIMITER = ';'
|
||||
const val DERIVATION_PATH_DELIMITER = 'd'
|
||||
private const val PREFIX_DELIMITER = '_'
|
||||
private const val SUFFIX_DELIMITER = ';'
|
||||
private const val DERIVATION_PATH_DELIMITER = 'd'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a blockchain network, identified by a unique ID, a human-readable name, and its standard type.
|
||||
|
|
@ -20,7 +19,7 @@ import kotlinx.parcelize.Parcelize
|
|||
* that cannot be represented in a fiat currency.
|
||||
* (For those blockchains that have FeeResource instead of a standard type of fee)
|
||||
*/
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class Network(
|
||||
val id: ID,
|
||||
val backendId: String,
|
||||
|
|
@ -30,7 +29,7 @@ data class Network(
|
|||
val isTestnet: Boolean,
|
||||
val standardType: StandardType,
|
||||
val hasFiatFeeRate: Boolean,
|
||||
) : Parcelable {
|
||||
) {
|
||||
|
||||
init {
|
||||
require(name.isNotBlank()) { "Network name must not be blank" }
|
||||
|
|
@ -42,8 +41,8 @@ data class Network(
|
|||
* @property value The string representation of the network ID.
|
||||
*/
|
||||
@JvmInline
|
||||
@Parcelize
|
||||
value class ID(val value: String) : Parcelable {
|
||||
@Serializable
|
||||
value class ID(val value: String) {
|
||||
|
||||
init {
|
||||
require(value.isNotBlank()) { "Network ID must not be blank" }
|
||||
|
|
@ -56,8 +55,8 @@ data class Network(
|
|||
* This class represents such paths in a generic manner, allowing for predefined card-based paths,
|
||||
* custom paths, or even no derivation path at all.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class DerivationPath : Parcelable {
|
||||
@Serializable
|
||||
sealed class DerivationPath {
|
||||
|
||||
/** The actual derivation path value, if any. */
|
||||
abstract val value: String?
|
||||
|
|
@ -67,6 +66,7 @@ data class Network(
|
|||
*
|
||||
* @property value The derivation path string.
|
||||
*/
|
||||
@Serializable
|
||||
data class Card(override val value: String) : DerivationPath()
|
||||
|
||||
/**
|
||||
|
|
@ -74,12 +74,14 @@ data class Network(
|
|||
*
|
||||
* @property value The derivation path string.
|
||||
*/
|
||||
@Serializable
|
||||
data class Custom(override val value: String) : DerivationPath()
|
||||
|
||||
/**
|
||||
* Represents a lack of derivation path.
|
||||
*/
|
||||
object None : DerivationPath() {
|
||||
@Serializable
|
||||
data object None : DerivationPath() {
|
||||
override val value: String? get() = null
|
||||
}
|
||||
}
|
||||
|
|
@ -93,31 +95,36 @@ data class Network(
|
|||
*
|
||||
* @property name The human-readable name of the standard type.
|
||||
*/
|
||||
@Parcelize
|
||||
sealed class StandardType : Parcelable {
|
||||
@Serializable
|
||||
sealed class StandardType {
|
||||
abstract val name: String
|
||||
|
||||
/** Represents the ERC20 token standard, common on the Ethereum network. */
|
||||
object ERC20 : StandardType() {
|
||||
@Serializable
|
||||
data object ERC20 : StandardType() {
|
||||
override val name: String get() = "ERC20"
|
||||
}
|
||||
|
||||
/** Represents the TRC20 token standard, common on the TRON network. */
|
||||
object TRC20 : StandardType() {
|
||||
@Serializable
|
||||
data object TRC20 : StandardType() {
|
||||
override val name: String get() = "TRC20"
|
||||
}
|
||||
|
||||
/** Represents the BEP20 token standard, common on the Binance Smart Chain network. */
|
||||
object BEP20 : StandardType() {
|
||||
@Serializable
|
||||
data object BEP20 : StandardType() {
|
||||
override val name: String get() = "BEP20"
|
||||
}
|
||||
|
||||
/** Represents the BEP2 token standard, common on the Binance Chain network. */
|
||||
object BEP2 : StandardType() {
|
||||
@Serializable
|
||||
data object BEP2 : StandardType() {
|
||||
override val name: String get() = "BEP2"
|
||||
}
|
||||
|
||||
/** Represents a network that does not adhere to a predefined standard type. */
|
||||
@Serializable
|
||||
data class Unspecified(override val name: String) : StandardType()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
|
|
@ -11,4 +12,8 @@ dependencies {
|
|||
// region Domain modules
|
||||
implementation(project(":domain:models"))
|
||||
// endregion
|
||||
|
||||
// region Other libraries
|
||||
implementation(deps.kotlin.serialization)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -2,9 +2,10 @@ package com.tangem.domain.wallets.models
|
|||
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import java.io.Serializable
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
data class UserWalletId(val stringValue: String) : Serializable {
|
||||
@Serializable
|
||||
data class UserWalletId(val stringValue: String) {
|
||||
|
||||
val value = stringValue.hexToBytes()
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ dependencies {
|
|||
|
||||
/* Project - Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
|
||||
/* AndroidX */
|
||||
implementation(deps.androidx.fragment.ktx)
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.features.details
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
interface DetailsEntryPoint {
|
||||
|
||||
fun entryFragment(): Fragment
|
||||
|
||||
companion object {
|
||||
|
||||
const val USER_WALLET_ID_KEY = "user_wallet_id"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,15 @@
|
|||
package com.tangem.features.details.component
|
||||
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface DetailsComponent : ComposableContentComponent {
|
||||
|
||||
val snackbarHostState: SnackbarHostState
|
||||
interface Factory : ComponentFactory<DetailsComponent, Params> {
|
||||
|
||||
interface Factory {
|
||||
|
||||
fun create(context: AppComponentContext, params: Params): DetailsComponent
|
||||
override fun create(context: AppComponentContext, params: Params): DetailsComponent
|
||||
}
|
||||
|
||||
data class Params(
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue