Updated on 2026-08-14
This commit is contained in:
commit
9c868cf221
202 changed files with 4333 additions and 775 deletions
|
|
@ -1,14 +1,21 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
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
|
||||
|
|
@ -16,14 +23,20 @@ import androidx.lifecycle.flowWithLifecycle
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.data.card.sdk.CardSdkLifecycleObserver
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.features.managetokens.navigation.ManageTokensRouter
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
import com.tangem.features.wallet.navigation.WalletRouter
|
||||
|
|
@ -46,12 +59,15 @@ import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandle
|
|||
import com.tangem.tap.features.intentHandler.handlers.BuyCurrencyIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.SellCurrencyIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
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.shop.redux.ShopAction
|
||||
import com.tangem.tap.features.welcome.ui.WelcomeFragment
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.ActivityMainBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -109,9 +125,17 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
lateinit var tokenDetailsRouter: TokenDetailsRouter
|
||||
|
||||
@Inject
|
||||
lateinit var manageTokensRouter: ManageTokensRouter
|
||||
|
||||
@Inject
|
||||
lateinit var walletConnectInteractor: WalletConnectInteractor
|
||||
|
||||
@Inject
|
||||
lateinit var sendRouter: SendRouter
|
||||
|
||||
internal val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode?>
|
||||
|
||||
// TODO: fixme: inject through DI
|
||||
|
|
@ -136,6 +160,29 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
initContent()
|
||||
|
||||
checkGooglePayAvailability()
|
||||
|
||||
checkForNotificationPermission()
|
||||
observeStateUpdates()
|
||||
}
|
||||
|
||||
private fun observeStateUpdates() {
|
||||
viewModel.state
|
||||
.flowWithLifecycle(lifecycle)
|
||||
.onEach { state ->
|
||||
if (state.toast is StateEvent.Triggered) {
|
||||
showToast(state.toast.data)
|
||||
state.toast.onConsume()
|
||||
}
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
private fun showToast(toast: Toast) {
|
||||
dismissSnackbar()
|
||||
showSnackbar(toast.message, Snackbar.LENGTH_LONG, toast.action.text) {
|
||||
toast.action.onClick()
|
||||
dismissSnackbar()
|
||||
}
|
||||
}
|
||||
|
||||
private fun installActivityDependencies() {
|
||||
|
|
@ -156,7 +203,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
walletRouter = walletRouter,
|
||||
walletConnectInteractor = walletConnectInteractor,
|
||||
tokenDetailsRouter = tokenDetailsRouter,
|
||||
manageTokensRouter = manageTokensRouter,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
sendRouter = sendRouter,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -285,18 +334,22 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
}
|
||||
|
||||
override fun showSnackbar(text: Int, buttonTitle: Int?, action: View.OnClickListener?) {
|
||||
if (snackbar != null) return
|
||||
override fun showSnackbar(
|
||||
@StringRes text: Int,
|
||||
length: Int,
|
||||
@StringRes buttonTitle: Int?,
|
||||
action: View.OnClickListener?,
|
||||
) {
|
||||
showSnackbar(getString(text), length, buttonTitle?.let(::getString), action)
|
||||
}
|
||||
|
||||
snackbar = Snackbar.make(
|
||||
binding.fragmentContainer,
|
||||
getString(text),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
)
|
||||
if (buttonTitle != null && action != null) {
|
||||
snackbar?.setAction(getString(buttonTitle), action)
|
||||
}
|
||||
snackbar?.show()
|
||||
override fun showSnackbar(
|
||||
text: TextReference,
|
||||
length: Int,
|
||||
buttonTitle: TextReference?,
|
||||
action: View.OnClickListener?,
|
||||
) {
|
||||
showSnackbar(text.resolveReference(resources), length, buttonTitle?.resolveReference(resources), action)
|
||||
}
|
||||
|
||||
override fun dismissSnackbar() {
|
||||
|
|
@ -332,6 +385,33 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
lockUserWalletsTimer?.restart()
|
||||
}
|
||||
|
||||
private fun showSnackbar(text: String, length: Int, buttonTitle: String?, action: View.OnClickListener?) {
|
||||
if (snackbar != null) return
|
||||
|
||||
snackbar = Snackbar.make(binding.fragmentContainer, text, length).apply {
|
||||
val textColor = getColor(R.color.text_primary_2)
|
||||
|
||||
setBackgroundTint(getColor(R.color.button_primary))
|
||||
setActionTextColor(textColor)
|
||||
setTextColor(textColor)
|
||||
|
||||
if (buttonTitle != null && action != null) {
|
||||
setAction(buttonTitle, action)
|
||||
}
|
||||
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
snackbar = null
|
||||
removeCallback(this)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
snackbar?.show()
|
||||
}
|
||||
|
||||
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
||||
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
||||
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
||||
|
|
@ -371,4 +451,14 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||
}
|
||||
|
||||
private fun checkForNotificationPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
||||
BuildConfig.DEBUG &&
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) !=
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import android.content.Context
|
|||
import android.content.pm.PackageManager
|
||||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.orhanobut.logger.AndroidLogAdapter
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.tangem.Log
|
||||
|
|
@ -36,6 +37,8 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
|||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
|
|
@ -170,6 +173,9 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
|||
// @Inject
|
||||
// lateinit var learn2earnInteractor: Learn2earnInteractor
|
||||
|
||||
@Inject
|
||||
lateinit var manageTokensFeatureToggles: ManageTokensFeatureToggles
|
||||
|
||||
@Inject
|
||||
lateinit var scanCardProcessor: ScanCardProcessor
|
||||
|
||||
|
|
@ -211,6 +217,9 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
|||
|
||||
@Inject
|
||||
lateinit var walletsRepository: WalletsRepository
|
||||
|
||||
@Inject
|
||||
lateinit var sendFeatureToggles: SendFeatureToggles
|
||||
// endregion Injected
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
@ -255,6 +264,7 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
|||
if (LogConfig.network.blockchainSdkNetwork) {
|
||||
BlockchainSdkRetrofitBuilder.interceptors = listOf(
|
||||
createNetworkLoggingInterceptor(),
|
||||
ChuckerInterceptor(this),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -290,6 +300,7 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
|||
walletFeatureToggles = walletFeatureToggles,
|
||||
walletConnectRepository = walletConnect2Repository,
|
||||
walletConnectSessionsRepository = walletConnectSessionsRepository,
|
||||
manageTokensFeatureToggles = manageTokensFeatureToggles,
|
||||
scanCardProcessor = scanCardProcessor,
|
||||
appCurrencyRepository = appCurrencyRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
|
|
@ -300,6 +311,7 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
|||
balanceHidingRepository = balanceHidingRepository,
|
||||
detailsFeatureToggles = detailsFeatureToggles,
|
||||
walletsRepository = walletsRepository,
|
||||
sendFeatureToggles = sendFeatureToggles,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,25 @@
|
|||
package com.tangem.tap.common
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
interface SnackbarHandler {
|
||||
fun showSnackbar(text: Int, buttonTitle: Int? = null, action: View.OnClickListener? = null)
|
||||
|
||||
fun showSnackbar(
|
||||
@StringRes text: Int,
|
||||
length: Int = Snackbar.LENGTH_INDEFINITE,
|
||||
@StringRes buttonTitle: Int? = null,
|
||||
action: View.OnClickListener? = null,
|
||||
)
|
||||
|
||||
fun showSnackbar(
|
||||
text: TextReference,
|
||||
length: Int = Snackbar.LENGTH_INDEFINITE,
|
||||
buttonTitle: TextReference? = null,
|
||||
action: View.OnClickListener? = null,
|
||||
)
|
||||
|
||||
fun dismissSnackbar()
|
||||
}
|
||||
|
|
@ -1,56 +1,7 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.extensions.remove
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
@DrawableRes
|
||||
fun Blockchain.getGreyedOutIconRes(): Int {
|
||||
return when (this) {
|
||||
Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> R.drawable.ic_arbitrum_no_color
|
||||
Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> R.drawable.ic_bitcoin_no_color
|
||||
Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_no_color
|
||||
Blockchain.Litecoin -> R.drawable.ic_litecoin_no_color
|
||||
Blockchain.Ethereum, Blockchain.EthereumTestnet -> R.drawable.ic_eth_no_color
|
||||
Blockchain.EthereumClassic, Blockchain.EthereumClassicTestnet -> R.drawable.ic_eth_no_color
|
||||
Blockchain.RSK -> R.drawable.ic_rsk_no_color
|
||||
Blockchain.Cardano -> R.drawable.ic_cardano_no_color
|
||||
Blockchain.Tezos -> R.drawable.ic_tezos_no_color
|
||||
Blockchain.XRP -> R.drawable.ic_xrp_no_color
|
||||
Blockchain.Stellar -> R.drawable.ic_stellar_no_color
|
||||
Blockchain.Avalanche, Blockchain.AvalancheTestnet -> R.drawable.ic_avalanche_no_color
|
||||
Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_no_color
|
||||
Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_no_color
|
||||
Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_no_color
|
||||
Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet ->
|
||||
R.drawable.ic_bsc_no_color
|
||||
Blockchain.Dogecoin -> R.drawable.ic_dogecoin_no_color
|
||||
Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_no_color
|
||||
Blockchain.Gnosis -> R.drawable.ic_gnosis_no_color
|
||||
Blockchain.EthereumPow, Blockchain.EthereumPowTestnet -> R.drawable.ic_ethereumpow_no_color
|
||||
Blockchain.EthereumFair -> R.drawable.ic_ethereumfair_no_color
|
||||
Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.drawable.ic_polkadot_no_color
|
||||
Blockchain.Kusama -> R.drawable.ic_kusama_no_color
|
||||
Blockchain.Optimism, Blockchain.OptimismTestnet -> R.drawable.ic_optimism_no_color
|
||||
Blockchain.Dash -> R.drawable.ic_dash_no_color
|
||||
Blockchain.Kaspa -> R.drawable.ic_kaspa_no_color
|
||||
Blockchain.TON, Blockchain.TONTestnet -> R.drawable.ic_ton_no_color
|
||||
Blockchain.Kava, Blockchain.KavaTestnet -> R.drawable.ic_kava_no_color
|
||||
Blockchain.Ravencoin, Blockchain.RavencoinTestnet -> R.drawable.ic_ravencoin_no_color
|
||||
Blockchain.Cosmos, Blockchain.CosmosTestnet -> R.drawable.ic_cosmos_no_color
|
||||
Blockchain.TerraV1 -> R.drawable.ic_terra_no_color
|
||||
Blockchain.TerraV2 -> R.drawable.ic_terra2_no_color
|
||||
Blockchain.Cronos -> R.drawable.ic_cronos_no_color
|
||||
Blockchain.Telos, Blockchain.TelosTestnet -> R.drawable.ic_telos_no_color
|
||||
Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> R.drawable.ic_azero_no_color
|
||||
Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> R.drawable.ic_octaspace_no_color
|
||||
Blockchain.Chia, Blockchain.ChiaTestnet -> R.drawable.ic_chia_no_color
|
||||
Blockchain.Near, Blockchain.NearTestnet -> R.drawable.ic_near_no_color
|
||||
else -> R.drawable.ic_tangem_logo
|
||||
}
|
||||
}
|
||||
|
||||
fun Blockchain.getNetworkName(): String {
|
||||
return when (this) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.tap.features.details.ui.walletconnect.QrScanFragment
|
|||
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.TwinsCardsFragment
|
||||
|
|
@ -59,12 +60,8 @@ fun FragmentActivity.openFragment(
|
|||
}
|
||||
}
|
||||
|
||||
if (screen.isDialogFragment) {
|
||||
val dialogFragment = requireNotNull(fragment as? DialogFragment) {
|
||||
"If screen.isDialogFragment == true then fragment must be a DialogFragment"
|
||||
}
|
||||
|
||||
dialogFragment.showAllowingStateLoss(
|
||||
if (screen.isDialogFragment && fragment is DialogFragment) {
|
||||
fragment.showAllowingStateLoss(
|
||||
fragmentManager = supportFragmentManager,
|
||||
baseTransaction = transaction,
|
||||
tag = screen.name,
|
||||
|
|
@ -125,7 +122,7 @@ fun FragmentActivity.getPreviousScreen(): AppScreen? {
|
|||
return tag?.let { AppScreen.valueOf(tag) }
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
@Suppress("ComplexMethod", "LongMethod")
|
||||
private fun fragmentFactory(screen: AppScreen): Fragment {
|
||||
return when (screen) {
|
||||
AppScreen.Home -> HomeFragment()
|
||||
|
|
@ -146,7 +143,18 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
|
|||
WalletFragment()
|
||||
}
|
||||
}
|
||||
AppScreen.Send -> SendFragment()
|
||||
AppScreen.Send -> {
|
||||
val featureToggles = store.state.daggerGraphState.get(
|
||||
getDependency = DaggerGraphState::sendFeatureToggles,
|
||||
)
|
||||
if (featureToggles.isRedesignedSendEnabled) {
|
||||
store.state.daggerGraphState
|
||||
.get(getDependency = DaggerGraphState::sendRouter)
|
||||
.getEntryFragment()
|
||||
} else {
|
||||
SendFragment()
|
||||
}
|
||||
}
|
||||
AppScreen.Details -> DetailsFragment()
|
||||
AppScreen.DetailsSecurity -> SecurityModeFragment()
|
||||
AppScreen.CardSettings -> CardSettingsFragment()
|
||||
|
|
@ -154,7 +162,18 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
|
|||
AppScreen.ResetToFactory -> ResetCardFragment()
|
||||
AppScreen.AccessCodeRecovery -> AccessCodeRecoveryFragment()
|
||||
AppScreen.Disclaimer -> DisclaimerFragment()
|
||||
AppScreen.AddTokens -> TokensListFragment()
|
||||
AppScreen.ManageTokens -> {
|
||||
val featureToggles = store.state.daggerGraphState.get(
|
||||
getDependency = DaggerGraphState::manageTokensFeatureToggles,
|
||||
)
|
||||
if (featureToggles.isRedesignedScreenEnabled) {
|
||||
store.state.daggerGraphState
|
||||
.get(getDependency = DaggerGraphState::manageTokensRouter)
|
||||
.getEntryFragment()
|
||||
} else {
|
||||
TokensListFragment()
|
||||
}
|
||||
}
|
||||
AppScreen.AddCustomToken -> AddCustomTokenFragment()
|
||||
AppScreen.WalletDetails -> {
|
||||
val featureToggles = store.state.daggerGraphState.get(
|
||||
|
|
@ -176,5 +195,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
|
|||
AppScreen.SaveWallet -> SaveWalletBottomSheetFragment()
|
||||
AppScreen.WalletSelector -> WalletSelectorBottomSheetFragment()
|
||||
AppScreen.AppCurrencySelector -> AppCurrencySelectorFragment()
|
||||
AppScreen.ModalNotification -> ModalNotificationBottomSheetFragment()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.balancehiding.DeviceFlipDetector
|
||||
import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.balancehiding.ListenToFlipsUseCase
|
||||
import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||
import com.tangem.domain.settings.*
|
||||
import com.tangem.domain.settings.repositories.AppRatingRepository
|
||||
|
|
@ -63,8 +64,10 @@ internal object SettingsDomainModule {
|
|||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesIsBalanceHiddenUseCase(balanceHidingRepository: BalanceHidingRepository): IsBalanceHiddenUseCase {
|
||||
return IsBalanceHiddenUseCase(
|
||||
fun providesGetBalanceHidingSettingsUseCase(
|
||||
balanceHidingRepository: BalanceHidingRepository,
|
||||
): GetBalanceHidingSettingsUseCase {
|
||||
return GetBalanceHidingSettingsUseCase(
|
||||
balanceHidingRepository = balanceHidingRepository,
|
||||
)
|
||||
}
|
||||
|
|
@ -80,4 +83,12 @@ internal object SettingsDomainModule {
|
|||
balanceHidingRepository = balanceHidingRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideUpdateHideBalancesSettingsUseCase(
|
||||
balanceHidingRepository: BalanceHidingRepository,
|
||||
): UpdateBalanceHidingSettingsUseCase {
|
||||
return UpdateBalanceHidingSettingsUseCase(balanceHidingRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.balancehiding.BalanceHidingSettings
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -280,7 +279,7 @@ class DetailsMiddleware {
|
|||
val repository = store.state.daggerGraphState.get(DaggerGraphState::balanceHidingRepository)
|
||||
|
||||
scope.launch {
|
||||
val newState = BalanceHidingSettings(
|
||||
val newState = repository.getBalanceHidingSettings().copy(
|
||||
isHidingEnabledInSettings = hideBalance,
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class HomeFragment : ComposeFragment(), StoreSubscriber<HomeState> {
|
|||
},
|
||||
onSearchTokensClick = {
|
||||
Analytics.send(IntroductionProcess.ButtonTokensList())
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.ManageTokens))
|
||||
store.dispatch(TokensAction.SetArgs.ReadAccess)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.features.main
|
||||
|
||||
internal interface MainIntents {
|
||||
|
||||
fun onHiddenBalanceToastAction()
|
||||
|
||||
fun onShownBalanceToastAction()
|
||||
|
||||
fun onHiddenBalanceNotificationAction(isPermanent: Boolean)
|
||||
|
||||
fun onDismissBottomSheet()
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.tangem.tap.features.main
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.tap.features.main.model.MainScreenState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
internal class MainScreenStateHolder(private val intents: MainIntents) {
|
||||
|
||||
private val notificationsFactory = NotificationsFactory(intents)
|
||||
|
||||
private val stateFlowInternal: MutableStateFlow<MainScreenState> = MutableStateFlow(getInitialState())
|
||||
|
||||
val stateFlow: StateFlow<MainScreenState> = stateFlowInternal
|
||||
|
||||
fun updateWithHiddenBalancesToast(isBalanceHidden: Boolean) {
|
||||
stateFlowInternal.update { state ->
|
||||
state.copy(
|
||||
toast = triggeredEvent(
|
||||
data = if (isBalanceHidden) {
|
||||
notificationsFactory.createBalancesAreHiddenToast()
|
||||
} else {
|
||||
notificationsFactory.createBalancesAreShownToast()
|
||||
},
|
||||
onConsume = ::consumeToastEvent,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateWithHiddenBalancesNotification() {
|
||||
stateFlowInternal.update { state ->
|
||||
state.copy(
|
||||
modalNotification = TangemBottomSheetConfig(
|
||||
isShow = true,
|
||||
onDismissRequest = intents::onDismissBottomSheet,
|
||||
content = notificationsFactory.createBalancesAreHiddenModalNotification(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateWithoutModalNotification() {
|
||||
stateFlowInternal.update { state ->
|
||||
state.copy(modalNotification = state.modalNotification?.copy(isShow = false))
|
||||
}
|
||||
}
|
||||
|
||||
private fun consumeToastEvent() {
|
||||
stateFlowInternal.update { state ->
|
||||
state.copy(toast = consumedEvent())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInitialState() = MainScreenState(
|
||||
toast = consumedEvent(),
|
||||
modalNotification = null,
|
||||
)
|
||||
}
|
||||
127
app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt
Normal file
127
app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package com.tangem.tap.features.main
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.ReduxNavController
|
||||
import com.tangem.domain.balancehiding.BalanceHidingSettings
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.balancehiding.ListenToFlipsUseCase
|
||||
import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
||||
import com.tangem.tap.features.main.model.MainScreenState
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class MainViewModel @Inject constructor(
|
||||
private val updateBalanceHidingSettingsUseCase: UpdateBalanceHidingSettingsUseCase,
|
||||
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
||||
private val reduxNavController: ReduxNavController,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
) : ViewModel(), MainIntents {
|
||||
|
||||
private val stateHolder = MainScreenStateHolder(
|
||||
intents = this,
|
||||
)
|
||||
|
||||
private val balanceHidingSettingsFlow: SharedFlow<BalanceHidingSettings> = getBalanceHidingSettingsUseCase()
|
||||
.shareIn(viewModelScope, SharingStarted.WhileSubscribed())
|
||||
|
||||
val state: StateFlow<MainScreenState> = stateHolder.stateFlow
|
||||
|
||||
init {
|
||||
observeFlips()
|
||||
displayBalancesHidingStatusToast()
|
||||
displayHiddenBalancesModalNotification()
|
||||
}
|
||||
|
||||
private fun observeFlips() {
|
||||
listenToFlipsUseCase().launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun displayHiddenBalancesModalNotification() {
|
||||
balanceHidingSettingsFlow
|
||||
.drop(count = 1) // Skip initial emit
|
||||
.distinctUntilChanged()
|
||||
.filter {
|
||||
it.isBalanceHidingNotificationEnabled && it.isBalanceHidden
|
||||
}
|
||||
.onEach {
|
||||
if (state.value.modalNotification?.isShow != true) {
|
||||
stateHolder.updateWithHiddenBalancesNotification()
|
||||
reduxNavController.navigate(NavigationAction.NavigateTo(AppScreen.ModalNotification))
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun displayBalancesHidingStatusToast() {
|
||||
var previousSettings: BalanceHidingSettings? = null
|
||||
|
||||
balanceHidingSettingsFlow
|
||||
.onEach { settings ->
|
||||
if (previousSettings == null) {
|
||||
previousSettings = settings
|
||||
return@onEach
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip if the feature to hide balances has just been
|
||||
* enabled or disabled in the settings, or if the hide balances status has not been changed
|
||||
* */
|
||||
if (settings.isHidingEnabledInSettings != previousSettings?.isHidingEnabledInSettings ||
|
||||
settings.isBalanceHidden == previousSettings?.isBalanceHidden
|
||||
) {
|
||||
previousSettings = settings
|
||||
return@onEach
|
||||
}
|
||||
|
||||
displayBalancesHiddenStatusToast(settings)
|
||||
|
||||
previousSettings = settings
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun displayBalancesHiddenStatusToast(settings: BalanceHidingSettings) {
|
||||
// If modal notification is enabled and balances are hidden, the toast will not show
|
||||
if (!settings.isBalanceHidingNotificationEnabled || !settings.isBalanceHidden) {
|
||||
stateHolder.updateWithHiddenBalancesToast(settings.isBalanceHidden)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHiddenBalanceToastAction() {
|
||||
viewModelScope.launch {
|
||||
updateBalanceHidingSettingsUseCase.invoke {
|
||||
copy(isBalanceHidden = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onShownBalanceToastAction() {
|
||||
viewModelScope.launch {
|
||||
updateBalanceHidingSettingsUseCase.invoke {
|
||||
copy(isBalanceHidden = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHiddenBalanceNotificationAction(isPermanent: Boolean) {
|
||||
onDismissBottomSheet()
|
||||
|
||||
if (isPermanent) {
|
||||
viewModelScope.launch {
|
||||
updateBalanceHidingSettingsUseCase.invoke {
|
||||
copy(isBalanceHidingNotificationEnabled = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismissBottomSheet() {
|
||||
stateHolder.updateWithoutModalNotification()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.tangem.tap.features.main
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.tap.features.main.model.ActionConfig
|
||||
import com.tangem.tap.features.main.model.ModalNotification
|
||||
import com.tangem.tap.features.main.model.Toast
|
||||
import com.tangem.wallet.R
|
||||
|
||||
internal class NotificationsFactory(
|
||||
private val intents: MainIntents,
|
||||
) {
|
||||
|
||||
fun createBalancesAreHiddenToast(): Toast {
|
||||
return Toast(
|
||||
message = resourceReference(R.string.toast_balances_hidden),
|
||||
action = ActionConfig(
|
||||
text = resourceReference(R.string.toast_undo),
|
||||
onClick = intents::onHiddenBalanceToastAction,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun createBalancesAreShownToast(): Toast {
|
||||
return Toast(
|
||||
message = resourceReference(R.string.toast_balances_shown),
|
||||
action = ActionConfig(
|
||||
text = resourceReference(R.string.toast_undo),
|
||||
onClick = intents::onShownBalanceToastAction,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun createBalancesAreHiddenModalNotification(): ModalNotification {
|
||||
return ModalNotification(
|
||||
iconResId = R.drawable.ic_eye_off_outline_24,
|
||||
title = resourceReference(R.string.balance_hidden_title),
|
||||
message = resourceReference(R.string.balance_hidden_description),
|
||||
primaryAction = ActionConfig(
|
||||
text = resourceReference(R.string.balance_hidden_got_it_button),
|
||||
onClick = { intents.onHiddenBalanceNotificationAction(isPermanent = false) },
|
||||
),
|
||||
secondaryAction = ActionConfig(
|
||||
text = resourceReference(R.string.balance_hidden_do_not_show_button),
|
||||
onClick = { intents.onHiddenBalanceNotificationAction(isPermanent = true) },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.features.main.model
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class ActionConfig(
|
||||
val text: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.tap.features.main.model
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
|
||||
internal data class MainScreenState(
|
||||
val toast: StateEvent<Toast>,
|
||||
val modalNotification: TangemBottomSheetConfig?,
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.tap.features.main.model
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class ModalNotification(
|
||||
@DrawableRes val iconResId: Int,
|
||||
val title: TextReference,
|
||||
val message: TextReference,
|
||||
val primaryAction: ActionConfig,
|
||||
val secondaryAction: ActionConfig?,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.features.main.model
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class Toast(
|
||||
val message: TextReference,
|
||||
val action: ActionConfig,
|
||||
)
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.tangem.tap.features.main.ui
|
||||
|
||||
import android.content.DialogInterface
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.screen.ComposeBottomSheetFragment
|
||||
import com.tangem.core.ui.theme.AppThemeModeHolder
|
||||
import com.tangem.tap.features.main.MainViewModel
|
||||
import com.tangem.tap.features.main.model.ModalNotification
|
||||
import com.tangem.tap.features.main.ui.components.ModalNotificationContent
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class ModalNotificationBottomSheetFragment : ComposeBottomSheetFragment() {
|
||||
|
||||
@Inject
|
||||
override lateinit var appThemeModeHolder: AppThemeModeHolder
|
||||
|
||||
private val viewModel: MainViewModel by activityViewModels()
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val notification = state.modalNotification
|
||||
if (notification == null) {
|
||||
dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
BackHandler(onBack = notification.onDismissRequest)
|
||||
|
||||
when (val content = notification.content) {
|
||||
is ModalNotification -> ModalNotificationContent(
|
||||
modifier = modifier,
|
||||
notification = content,
|
||||
)
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
LaunchedEffect(notification) {
|
||||
if (!notification.isShow) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
viewModel.state.value.modalNotification?.onDismissRequest?.invoke()
|
||||
super.onDismiss(dialog)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package com.tangem.tap.features.main.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.atoms.Hand
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.tap.features.main.model.ActionConfig
|
||||
import com.tangem.tap.features.main.model.ModalNotification
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
internal fun ModalNotificationContent(notification: ModalNotification, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing40),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Hand()
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size48),
|
||||
painter = painterResource(notification.iconResId),
|
||||
tint = TangemTheme.colors.icon.primary1,
|
||||
contentDescription = null,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = notification.title.resolveReference(),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = notification.message.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(bottom = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
PrimaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = notification.primaryAction.text.resolveReference(),
|
||||
onClick = notification.primaryAction.onClick,
|
||||
)
|
||||
when (val secondaryAction = notification.secondaryAction) {
|
||||
null -> Unit
|
||||
else -> SecondaryButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = secondaryAction.text.resolveReference(),
|
||||
onClick = secondaryAction.onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(widthDp = 360, heightDp = 404)
|
||||
@Composable
|
||||
private fun ModalNotificationContentPreview_Light(
|
||||
@PreviewParameter(GlobalNotificationProvider::class) param: ModalNotification,
|
||||
) {
|
||||
TangemTheme(isDark = false) {
|
||||
ModalNotificationContent(
|
||||
param,
|
||||
modifier = Modifier.background(
|
||||
color = TangemTheme.colors.background.plain,
|
||||
shape = TangemTheme.shapes.bottomSheet,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, heightDp = 404)
|
||||
@Composable
|
||||
private fun ModalNotificationContentPreview_Dark(
|
||||
@PreviewParameter(GlobalNotificationProvider::class) param: ModalNotification,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
ModalNotificationContent(
|
||||
param,
|
||||
modifier = Modifier.background(
|
||||
color = TangemTheme.colors.background.plain,
|
||||
shape = TangemTheme.shapes.bottomSheet,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class GlobalNotificationProvider : CollectionPreviewParameterProvider<ModalNotification>(
|
||||
collection = listOf(
|
||||
ModalNotification(
|
||||
iconResId = R.drawable.ic_eye_off_outline_24,
|
||||
title = resourceReference(R.string.balance_hidden_title),
|
||||
message = resourceReference(R.string.balance_hidden_description),
|
||||
primaryAction = ActionConfig(
|
||||
text = resourceReference(R.string.balance_hidden_got_it_button),
|
||||
onClick = {},
|
||||
),
|
||||
secondaryAction = ActionConfig(
|
||||
text = resourceReference(R.string.balance_hidden_do_not_show_button),
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -4,9 +4,7 @@ import com.google.android.material.button.MaterialButton
|
|||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.postUiDelayBg
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.FIRST_BACKUP
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.ORIGIN
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.SECOND_BACKUP
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.BackupCardType.*
|
||||
import com.tangem.wallet.databinding.FragmentOnboardingWalletBinding
|
||||
|
||||
/**
|
||||
|
|
@ -29,7 +27,7 @@ class WalletBackupAnimator(
|
|||
|
||||
private val viewState: State = when (cardsWidget.leapfrogWidget.getViewsCount()) {
|
||||
2 -> State.TwoCards
|
||||
3 -> State.TreeCards
|
||||
3 -> State.ThreeCards
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +129,7 @@ class WalletBackupAnimator(
|
|||
}
|
||||
}
|
||||
}
|
||||
State.TreeCards -> {
|
||||
State.ThreeCards -> {
|
||||
when (backupCard) {
|
||||
1 -> {
|
||||
if (firstBackupCardAnimated) return
|
||||
|
|
@ -147,6 +145,15 @@ class WalletBackupAnimator(
|
|||
if (secondBackupCardAnimated) return
|
||||
secondBackupCardAnimated = true
|
||||
|
||||
/*
|
||||
* !!! Workaround !!!
|
||||
* For interrupted backup
|
||||
* */
|
||||
if (!firstBackupCardAnimated) {
|
||||
showWriteBackupCard(state, backupCard = 1)
|
||||
return
|
||||
}
|
||||
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
cardsWidget.leapfrogWidget.leap {
|
||||
ORIGIN.alpha(0.4f)
|
||||
|
|
@ -165,7 +172,7 @@ class WalletBackupAnimator(
|
|||
}
|
||||
|
||||
private enum class State {
|
||||
TreeCards,
|
||||
ThreeCards,
|
||||
TwoCards,
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +193,7 @@ class WalletBackupAnimator(
|
|||
}
|
||||
}
|
||||
SECOND_BACKUP -> {
|
||||
if (viewState != State.TreeCards) return
|
||||
if (viewState != State.ThreeCards) return
|
||||
cardsWidget.getSecondBackupCardView().animate().apply {
|
||||
alpha(alpha)
|
||||
this.startDelay = startDelay
|
||||
|
|
@ -201,7 +208,7 @@ class WalletBackupAnimator(
|
|||
ORIGIN -> cardsWidget.getOriginCardView().alpha = alpha
|
||||
FIRST_BACKUP -> cardsWidget.getFirstBackupCardView().alpha = alpha
|
||||
SECOND_BACKUP -> {
|
||||
if (viewState != State.TreeCards) return
|
||||
if (viewState != State.ThreeCards) return
|
||||
cardsWidget.getSecondBackupCardView().alpha = alpha
|
||||
}
|
||||
}
|
||||
|
|
@ -212,7 +219,7 @@ class WalletBackupAnimator(
|
|||
ORIGIN -> cardsWidget.getOriginCardView().show()
|
||||
FIRST_BACKUP -> cardsWidget.getFirstBackupCardView().show()
|
||||
SECOND_BACKUP -> {
|
||||
if (viewState != State.TreeCards) return
|
||||
if (viewState != State.ThreeCards) return
|
||||
cardsWidget.getSecondBackupCardView().show()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.send.ui
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.balancehiding.ListenToFlipsUseCase
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
|
|
@ -9,7 +9,7 @@ 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.navigation.SendRouter
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.tap.di.DelayedWork
|
||||
import com.tangem.tap.features.send.redux.AmountAction
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
|
|
@ -29,7 +29,7 @@ import javax.inject.Inject
|
|||
internal class SendViewModel @Inject constructor(
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val appStateHolder: AppStateHolder,
|
||||
private val isBalanceHiddenUseCase: IsBalanceHiddenUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
|
|
@ -41,11 +41,11 @@ internal class SendViewModel @Inject constructor(
|
|||
private val cryptoCurrency: CryptoCurrency? = savedStateHandle[SendRouter.CRYPTO_CURRENCY_KEY]
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
isBalanceHiddenUseCase()
|
||||
getBalanceHidingSettingsUseCase()
|
||||
.flowWithLifecycle(owner.lifecycle)
|
||||
.onEach { isBalanceHidden ->
|
||||
.onEach {
|
||||
withContext(dispatchers.main) {
|
||||
appStateHolder.mainStore?.dispatch(AmountAction.HideBalance(isBalanceHidden))
|
||||
appStateHolder.mainStore?.dispatch(AmountAction.HideBalance(it.isBalanceHidden))
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.tap.features.tokens.impl.presentation.states
|
|||
import androidx.compose.runtime.MutableState
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.tap.common.extensions.getGreyedOutIconRes
|
||||
import com.tangem.core.ui.extensions.getGreyedOutIconRes
|
||||
|
||||
/**
|
||||
* Network item state
|
||||
|
|
@ -76,7 +76,7 @@ sealed interface NetworkItemState {
|
|||
fun changeToggleState() {
|
||||
val reverseState = !isAdded.value
|
||||
isAdded.value = reverseState
|
||||
iconResId.value = if (reverseState) getActiveIconRes(blockchain.id) else blockchain.getGreyedOutIconRes()
|
||||
iconResId.value = if (reverseState) getActiveIconRes(blockchain.id) else getGreyedOutIconRes(blockchain.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ object TokenListPreviewData {
|
|||
NetworkItemState.ManageContent(
|
||||
name = "Ethereum",
|
||||
protocolName = "MAIN",
|
||||
iconResId = mutableStateOf(R.drawable.ic_eth_no_color),
|
||||
iconResId = mutableStateOf(R.drawable.ic_eth_16),
|
||||
isMainNetwork = true,
|
||||
isAdded = mutableStateOf(true),
|
||||
id = "",
|
||||
|
|
@ -53,7 +53,7 @@ object TokenListPreviewData {
|
|||
NetworkItemState.ManageContent(
|
||||
name = "BNB SMART CHAIN",
|
||||
protocolName = "BEP20",
|
||||
iconResId = mutableStateOf(R.drawable.ic_bsc_no_color),
|
||||
iconResId = mutableStateOf(R.drawable.ic_bsc_16),
|
||||
isMainNetwork = false,
|
||||
isAdded = mutableStateOf(false),
|
||||
id = "",
|
||||
|
|
@ -71,13 +71,13 @@ object TokenListPreviewData {
|
|||
NetworkItemState.ReadContent(
|
||||
name = "Ethereum",
|
||||
protocolName = "MAIN",
|
||||
iconResId = mutableStateOf(R.drawable.ic_eth_no_color),
|
||||
iconResId = mutableStateOf(R.drawable.ic_eth_16),
|
||||
isMainNetwork = true,
|
||||
),
|
||||
NetworkItemState.ReadContent(
|
||||
name = "BNB SMART CHAIN",
|
||||
protocolName = "BEP20",
|
||||
iconResId = mutableStateOf(R.drawable.ic_bsc_no_color),
|
||||
iconResId = mutableStateOf(R.drawable.ic_bsc_16),
|
||||
isMainNetwork = false,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import androidx.paging.*
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.core.ui.extensions.getGreyedOutIconRes
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.extensions.canHandleBlockchain
|
||||
import com.tangem.domain.common.extensions.canHandleToken
|
||||
|
|
@ -20,7 +21,6 @@ import com.tangem.domain.tokens.TokenWithBlockchain
|
|||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
|
||||
import com.tangem.tap.common.extensions.getGreyedOutIconRes
|
||||
import com.tangem.tap.common.extensions.getNetworkName
|
||||
import com.tangem.tap.features.tokens.impl.domain.TokensListInteractor
|
||||
import com.tangem.tap.features.tokens.impl.domain.models.Token
|
||||
|
|
@ -225,7 +225,7 @@ internal class TokensListViewModel @Inject constructor(
|
|||
return if (isAdded(address = address, blockchain = blockchain)) {
|
||||
getActiveIconRes(blockchain.id)
|
||||
} else {
|
||||
blockchain.getGreyedOutIconRes()
|
||||
getGreyedOutIconRes(blockchain.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
|||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.feature.swap.presentation.SwapFragment
|
||||
import com.tangem.features.send.navigation.SendRouter
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Token
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
|
|
@ -366,7 +366,10 @@ class TradeCryptoMiddleware {
|
|||
),
|
||||
)
|
||||
|
||||
val bundle = bundleOf(SendRouter.CRYPTO_CURRENCY_KEY to currency)
|
||||
val bundle = bundleOf(
|
||||
SendRouter.CRYPTO_CURRENCY_KEY to currency,
|
||||
SendRouter.USER_WALLET_ID_KEY to action.userWallet.walletId.stringValue,
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
|
||||
}
|
||||
}
|
||||
|
|
@ -416,7 +419,10 @@ class TradeCryptoMiddleware {
|
|||
is CryptoCurrency.Token -> error("Action.tokenStatus.currency is Token")
|
||||
}
|
||||
|
||||
val bundle = bundleOf(SendRouter.CRYPTO_CURRENCY_KEY to currency)
|
||||
val bundle = bundleOf(
|
||||
SendRouter.CRYPTO_CURRENCY_KEY to currency,
|
||||
SendRouter.USER_WALLET_ID_KEY to action.userWallet.walletId.stringValue,
|
||||
)
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class MultiWalletView : WalletView() {
|
|||
Analytics.send(Portfolio.ButtonManageTokens())
|
||||
|
||||
store.dispatch(action = TokensAction.SetArgs.ManageAccess)
|
||||
store.dispatch(action = NavigationAction.NavigateTo(screen = AppScreen.AddTokens))
|
||||
store.dispatch(action = NavigationAction.NavigateTo(screen = AppScreen.ManageTokens))
|
||||
}
|
||||
handleErrorStates(state = state, binding = binding, fragment = fragment)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.tangem.tap.proxy.redux
|
|||
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.features.managetokens.navigation.ManageTokensRouter
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
import com.tangem.features.wallet.navigation.WalletRouter
|
||||
|
|
@ -16,6 +18,8 @@ sealed interface DaggerGraphAction : Action {
|
|||
val walletRouter: WalletRouter,
|
||||
val walletConnectInteractor: WalletConnectInteractor,
|
||||
val tokenDetailsRouter: TokenDetailsRouter,
|
||||
val manageTokensRouter: ManageTokensRouter,
|
||||
val cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
val sendRouter: SendRouter,
|
||||
) : DaggerGraphAction
|
||||
}
|
||||
|
|
@ -18,7 +18,9 @@ object DaggerGraphReducer {
|
|||
walletRouter = action.walletRouter,
|
||||
walletConnectInteractor = action.walletConnectInteractor,
|
||||
tokenDetailsRouter = action.tokenDetailsRouter,
|
||||
manageTokensRouter = action.manageTokensRouter,
|
||||
cardSdkConfigRepository = action.cardSdkConfigRepository,
|
||||
sendRouter = action.sendRouter,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||
import com.tangem.features.managetokens.navigation.ManageTokensRouter
|
||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
|
|
@ -36,6 +40,8 @@ data class DaggerGraphState(
|
|||
val walletConnectSessionsRepository: WalletConnectSessionsRepository? = null,
|
||||
val walletConnectInteractor: WalletConnectInteractor? = null,
|
||||
val tokenDetailsRouter: TokenDetailsRouter? = null,
|
||||
val manageTokensFeatureToggles: ManageTokensFeatureToggles? = null,
|
||||
val manageTokensRouter: ManageTokensRouter? = null,
|
||||
val scanCardProcessor: ScanCardProcessor? = null,
|
||||
val cardSdkConfigRepository: CardSdkConfigRepository? = null,
|
||||
val appCurrencyRepository: AppCurrencyRepository? = null,
|
||||
|
|
@ -46,6 +52,8 @@ data class DaggerGraphState(
|
|||
val detailsFeatureToggles: DetailsFeatureToggles? = null,
|
||||
val walletsRepository: WalletsRepository? = null,
|
||||
val networksRepository: NetworksRepository? = null,
|
||||
val sendFeatureToggles: SendFeatureToggles? = null,
|
||||
val sendRouter: SendRouter? = null,
|
||||
|
||||
// FIXME: It is used only for TokensList screen. Remove after refactoring of TokensList
|
||||
val currenciesRepository: CurrenciesRepository? = null,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue