Updated on 2026-08-14
This commit is contained in:
commit
bc84d8f5f8
579 changed files with 13604 additions and 3422 deletions
|
|
@ -14,6 +14,11 @@ android {
|
||||||
testOptions {
|
testOptions {
|
||||||
animationsDisabled = true
|
animationsDisabled = true
|
||||||
}
|
}
|
||||||
|
packaging {
|
||||||
|
jniLibs {
|
||||||
|
useLegacyPackaging = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.all {
|
configurations.all {
|
||||||
|
|
@ -71,6 +76,7 @@ dependencies {
|
||||||
implementation(projects.domain.walletConnect)
|
implementation(projects.domain.walletConnect)
|
||||||
|
|
||||||
implementation(projects.common)
|
implementation(projects.common)
|
||||||
|
implementation(projects.common.routing)
|
||||||
implementation(projects.core.analytics)
|
implementation(projects.core.analytics)
|
||||||
implementation(projects.core.analytics.models)
|
implementation(projects.core.analytics.models)
|
||||||
implementation(projects.core.navigation)
|
implementation(projects.core.navigation)
|
||||||
|
|
@ -130,6 +136,12 @@ dependencies {
|
||||||
implementation(projects.features.staking.impl)
|
implementation(projects.features.staking.impl)
|
||||||
implementation(projects.features.details.api)
|
implementation(projects.features.details.api)
|
||||||
implementation(projects.features.details.impl)
|
implementation(projects.features.details.impl)
|
||||||
|
implementation(projects.features.disclaimer.api)
|
||||||
|
implementation(projects.features.disclaimer.impl)
|
||||||
|
implementation(projects.features.pushNotifications.api)
|
||||||
|
implementation(projects.features.pushNotifications.impl)
|
||||||
|
implementation(projects.features.walletSettings.api)
|
||||||
|
implementation(projects.features.walletSettings.impl)
|
||||||
|
|
||||||
/** AndroidX libraries */
|
/** AndroidX libraries */
|
||||||
implementation(deps.androidx.core.ktx)
|
implementation(deps.androidx.core.ktx)
|
||||||
|
|
@ -166,6 +178,7 @@ dependencies {
|
||||||
implementation(platform(deps.firebase.bom))
|
implementation(platform(deps.firebase.bom))
|
||||||
implementation(deps.firebase.analytics)
|
implementation(deps.firebase.analytics)
|
||||||
implementation(deps.firebase.crashlytics)
|
implementation(deps.firebase.crashlytics)
|
||||||
|
implementation(deps.firebase.messaging)
|
||||||
|
|
||||||
/** Tangem libraries */
|
/** Tangem libraries */
|
||||||
implementation(deps.tangem.blockchain) {
|
implementation(deps.tangem.blockchain) {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@
|
||||||
android:largeHeap="@bool/largeHeap"
|
android:largeHeap="@bool/largeHeap"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:extractNativeLibs="true"
|
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
tools:ignore="GoogleAppIndexingWarning"
|
tools:ignore="GoogleAppIndexingWarning"
|
||||||
tools:replace="android:allowBackup, android:fullBackupContent, android:label">
|
tools:replace="android:allowBackup, android:fullBackupContent, android:label">
|
||||||
|
|
@ -145,5 +144,12 @@
|
||||||
android:resource="@xml/provider_paths" />
|
android:resource="@xml/provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name="com.tangem.tap.common.pushes.TangemPushNotificationService"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,32 @@
|
||||||
package com.tangem.tap
|
package com.tangem.tap
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.hardware.biometrics.BiometricManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.Settings
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
|
||||||
interface ActivityResultCaller {
|
interface ActivityResultCaller {
|
||||||
val activityResultLauncher: ActivityResultLauncher<Intent>?
|
val activityResultLauncher: ActivityResultLauncher<Intent>?
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun ActivityResultCaller.openSystemBiometrySettings() {
|
||||||
|
val settingsAction = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
|
||||||
|
Settings.ACTION_BIOMETRIC_ENROLL
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Settings.ACTION_SECURITY_SETTINGS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val intent = Intent(settingsAction).apply {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
putExtra(
|
||||||
|
Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
|
||||||
|
BiometricManager.Authenticators.BIOMETRIC_STRONG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activityResultLauncher?.launch(intent)
|
||||||
}
|
}
|
||||||
|
|
@ -2,8 +2,11 @@ package com.tangem.tap
|
||||||
|
|
||||||
import com.tangem.TangemSdkLogger
|
import com.tangem.TangemSdkLogger
|
||||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||||
|
import com.tangem.core.navigation.share.ShareManager
|
||||||
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.datasource.asset.loader.AssetLoader
|
import com.tangem.datasource.asset.loader.AssetLoader
|
||||||
import com.tangem.datasource.config.ConfigManager
|
import com.tangem.datasource.config.ConfigManager
|
||||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||||
|
|
@ -26,9 +29,9 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||||
import com.tangem.features.details.DetailsEntryPoint
|
|
||||||
import com.tangem.features.details.DetailsFeatureToggles
|
import com.tangem.features.details.DetailsFeatureToggles
|
||||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||||
|
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
|
||||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectSessionsRepository
|
||||||
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
|
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
|
||||||
|
|
@ -109,5 +112,11 @@ interface ApplicationEntryPoint {
|
||||||
|
|
||||||
fun getDetailsFeatureToggles(): DetailsFeatureToggles
|
fun getDetailsFeatureToggles(): DetailsFeatureToggles
|
||||||
|
|
||||||
fun getDetailsEntryPoint(): DetailsEntryPoint
|
fun getUrlOpener(): UrlOpener
|
||||||
|
|
||||||
|
fun getShareManager(): ShareManager
|
||||||
|
|
||||||
|
fun getAppRouter(): AppRouter
|
||||||
|
|
||||||
|
fun getPushNotificationsFeatureToggles(): PushNotificationsFeatureToggles
|
||||||
}
|
}
|
||||||
71
app/src/main/java/com/tangem/tap/DecomposeFragment.kt
Normal file
71
app/src/main/java/com/tangem/tap/DecomposeFragment.kt
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.tangem.tap
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
|
import com.tangem.core.ui.UiDependencies
|
||||||
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.core.ui.message.EventMessageEffect
|
||||||
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
|
import com.tangem.utils.Provider
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import java.util.WeakHashMap
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
internal class DecomposeFragment : ComposeFragment() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
override lateinit var uiDependencies: UiDependencies
|
||||||
|
|
||||||
|
private val component by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||||
|
val tag = requireArguments().getString(TAG_KEY)
|
||||||
|
val builder = componentsBuilders[tag]
|
||||||
|
|
||||||
|
requireNotNull(builder?.build()) {
|
||||||
|
"Component builder is not set, call newInstance() for DecomposeFragment creation first."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun ScreenContent(modifier: Modifier) {
|
||||||
|
component.Content(modifier)
|
||||||
|
|
||||||
|
EventMessageEffect(
|
||||||
|
messageHandler = uiDependencies.eventMessageHandler,
|
||||||
|
snackbarHostState = uiDependencies.globalSnackbarHostState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ComponentBuilder<C : ComposableContentComponent, P : Any, F : ComponentFactory<P, C>>(
|
||||||
|
private val contextProvider: Provider<AppComponentContext>,
|
||||||
|
private val params: P,
|
||||||
|
private val componentFactory: F,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun build(): C = componentFactory.create(contextProvider(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG_KEY = "tag"
|
||||||
|
|
||||||
|
private val componentsBuilders = WeakHashMap<String, ComponentBuilder<*, *, *>>()
|
||||||
|
|
||||||
|
fun <C : ComposableContentComponent, P : Any, F : ComponentFactory<P, C>> newInstance(
|
||||||
|
tag: String,
|
||||||
|
contextProvider: Provider<AppComponentContext>,
|
||||||
|
params: P,
|
||||||
|
componentFactory: F,
|
||||||
|
): Fragment {
|
||||||
|
this@Companion.componentsBuilders[tag] = ComponentBuilder(contextProvider, params, componentFactory)
|
||||||
|
|
||||||
|
return DecomposeFragment().apply {
|
||||||
|
this.arguments = bundleOf(TAG_KEY to tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,13 +3,12 @@ package com.tangem.tap
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
import com.tangem.common.routing.utils.popTo
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.legacy.asLockable
|
import com.tangem.domain.wallets.legacy.asLockable
|
||||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
@ -50,7 +49,7 @@ internal class LockUserWalletsTimer(
|
||||||
start()
|
start()
|
||||||
|
|
||||||
if (shouldOpenWelcomeScreenOnResume) {
|
if (shouldOpenWelcomeScreenOnResume) {
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome))
|
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
||||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
|
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +127,7 @@ internal class LockUserWalletsTimer(
|
||||||
if (wasApplicationStopped) {
|
if (wasApplicationStopped) {
|
||||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = true)
|
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = true)
|
||||||
} else {
|
} else {
|
||||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Welcome))
|
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,39 @@
|
||||||
package com.tangem.tap
|
package com.tangem.tap
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.nfc.NfcAdapter
|
import android.nfc.NfcAdapter
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.SystemBarStyle
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.core.view.WindowCompat
|
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.flowWithLifecycle
|
import androidx.lifecycle.flowWithLifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
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.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
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.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.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.navigation.email.EmailSender
|
||||||
import com.tangem.core.ui.event.StateEvent
|
import com.tangem.core.ui.event.StateEvent
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
|
@ -40,6 +41,7 @@ import com.tangem.core.ui.extensions.resolveReference
|
||||||
import com.tangem.data.card.sdk.CardSdkLifecycleObserver
|
import com.tangem.data.card.sdk.CardSdkLifecycleObserver
|
||||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||||
import com.tangem.domain.card.ScanCardUseCase
|
import com.tangem.domain.card.ScanCardUseCase
|
||||||
|
import com.tangem.domain.card.repository.CardRepository
|
||||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||||
|
|
@ -47,8 +49,11 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||||
|
import com.tangem.features.disclaimer.api.DisclaimerRouter
|
||||||
import com.tangem.features.managetokens.navigation.ManageTokensUi
|
import com.tangem.features.managetokens.navigation.ManageTokensUi
|
||||||
|
import com.tangem.features.pushnotifications.api.navigation.PushNotificationsRouter
|
||||||
import com.tangem.features.send.api.navigation.SendRouter
|
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.tester.api.TesterRouter
|
||||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||||
import com.tangem.features.wallet.navigation.WalletRouter
|
import com.tangem.features.wallet.navigation.WalletRouter
|
||||||
|
|
@ -59,6 +64,9 @@ import com.tangem.tap.common.DialogManager
|
||||||
import com.tangem.tap.common.OnActivityResultCallback
|
import com.tangem.tap.common.OnActivityResultCallback
|
||||||
import com.tangem.tap.common.SnackbarHandler
|
import com.tangem.tap.common.SnackbarHandler
|
||||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||||
|
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||||
|
import com.tangem.tap.common.extensions.inject
|
||||||
|
import com.tangem.tap.common.extensions.showFragmentAllowingStateLoss
|
||||||
import com.tangem.tap.common.redux.NotificationsHandler
|
import com.tangem.tap.common.redux.NotificationsHandler
|
||||||
import com.tangem.tap.domain.sdk.TangemSdkManager
|
import com.tangem.tap.domain.sdk.TangemSdkManager
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||||
|
|
@ -68,17 +76,17 @@ import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHan
|
||||||
import com.tangem.tap.features.main.MainViewModel
|
import com.tangem.tap.features.main.MainViewModel
|
||||||
import com.tangem.tap.features.main.model.Toast
|
import com.tangem.tap.features.main.model.Toast
|
||||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
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.AppStateHolder
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||||
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
|
import com.tangem.tap.routing.RoutingComponent
|
||||||
|
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||||
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
|
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
|
||||||
import com.tangem.wallet.BuildConfig
|
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import com.tangem.wallet.databinding.ActivityMainBinding
|
import com.tangem.wallet.databinding.ActivityMainBinding
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
@ -158,6 +166,28 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var emailSender: EmailSender
|
lateinit var emailSender: EmailSender
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var disclaimerRouter: DisclaimerRouter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var pushNotificationsRouter: PushNotificationsRouter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var cardRepository: CardRepository
|
||||||
|
|
||||||
internal val viewModel: MainViewModel by viewModels()
|
internal val viewModel: MainViewModel by viewModels()
|
||||||
|
|
||||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode?>
|
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode?>
|
||||||
|
|
@ -176,6 +206,13 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
|
|
||||||
installAppTheme() // We need to call it before onCreate to prevent unnecessary activity recreation
|
installAppTheme() // We need to call it before onCreate to prevent unnecessary activity recreation
|
||||||
|
|
||||||
|
enableEdgeToEdge(
|
||||||
|
navigationBarStyle = SystemBarStyle.auto(
|
||||||
|
Color.Transparent.toArgb(),
|
||||||
|
Color.Transparent.toArgb(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
splashScreen.setKeepOnScreenCondition { viewModel.isSplashScreenShown }
|
splashScreen.setKeepOnScreenCondition { viewModel.isSplashScreenShown }
|
||||||
|
|
@ -184,9 +221,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
observeAppThemeModeUpdates()
|
observeAppThemeModeUpdates()
|
||||||
|
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
installRouting()
|
||||||
initContent()
|
initContent()
|
||||||
|
|
||||||
checkForNotificationPermission()
|
|
||||||
observeStateUpdates()
|
observeStateUpdates()
|
||||||
observePolkadotAccountHealthCheck()
|
observePolkadotAccountHealthCheck()
|
||||||
|
|
||||||
|
|
@ -195,6 +232,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() {
|
private fun observeStateUpdates() {
|
||||||
viewModel.state
|
viewModel.state
|
||||||
.flowWithLifecycle(lifecycle)
|
.flowWithLifecycle(lifecycle)
|
||||||
|
|
@ -216,8 +278,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installActivityDependencies() {
|
private fun installActivityDependencies() {
|
||||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
|
||||||
|
|
||||||
cardSdkLifecycleObserver.onCreate(context = this)
|
cardSdkLifecycleObserver.onCreate(context = this)
|
||||||
tangemSdkManager = injectedTangemSdkManager
|
tangemSdkManager = injectedTangemSdkManager
|
||||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||||
|
|
@ -242,6 +302,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
sendRouter = sendRouter,
|
sendRouter = sendRouter,
|
||||||
qrScanningRouter = qrScanningRouter,
|
qrScanningRouter = qrScanningRouter,
|
||||||
emailSender = emailSender,
|
emailSender = emailSender,
|
||||||
|
stakingRouter = stakingRouter,
|
||||||
|
disclaimerRouter = disclaimerRouter,
|
||||||
|
pushNotificationsRouter = pushNotificationsRouter,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -263,8 +326,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
private fun initContent() {
|
private fun initContent() {
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
||||||
|
|
||||||
supportFragmentManager.registerFragmentLifecycleCallbacks(
|
supportFragmentManager.registerFragmentLifecycleCallbacks(
|
||||||
NavBarInsetsFragmentLifecycleCallback(),
|
NavBarInsetsFragmentLifecycleCallback(),
|
||||||
true,
|
true,
|
||||||
|
|
@ -293,19 +354,21 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
|
val nfcAdapter: NfcAdapter? = NfcAdapter.getDefaultAdapter(this)
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
if (nfcAdapter?.isEnabled == true) {
|
||||||
this,
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
0,
|
this,
|
||||||
Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
0,
|
||||||
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
||||||
)
|
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
||||||
val intentFilters = arrayOf(
|
)
|
||||||
IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED),
|
val intentFilters = arrayOf(
|
||||||
IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED),
|
IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED),
|
||||||
IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED),
|
IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED),
|
||||||
)
|
IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED),
|
||||||
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null)
|
)
|
||||||
|
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null)
|
||||||
|
}
|
||||||
// TODO: RESEARCH! NotificationsHandler is created in onResume and destroyed in onStop
|
// TODO: RESEARCH! NotificationsHandler is created in onResume and destroyed in onStop
|
||||||
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
|
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
|
||||||
|
|
||||||
|
|
@ -314,8 +377,11 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
val nfcAdapter = NfcAdapter.getDefaultAdapter(this)
|
val nfcAdapter: NfcAdapter? = NfcAdapter.getDefaultAdapter(this)
|
||||||
nfcAdapter.disableForegroundDispatch(this)
|
|
||||||
|
if (nfcAdapter?.isEnabled == true) {
|
||||||
|
nfcAdapter.disableForegroundDispatch(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
|
@ -325,7 +391,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this)))
|
|
||||||
intentProcessor.removeAll()
|
intentProcessor.removeAll()
|
||||||
cardSdkLifecycleObserver.onDestroy(this)
|
cardSdkLifecycleObserver.onDestroy(this)
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
@ -467,17 +532,16 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
|
|
||||||
private fun navigateToInitialScreen(intentWhichStartedActivity: Intent?) {
|
private fun navigateToInitialScreen(intentWhichStartedActivity: Intent?) {
|
||||||
if (userWalletsListManager.isLockable && userWalletsListManager.hasUserWallets) {
|
if (userWalletsListManager.isLockable && userWalletsListManager.hasUserWallets) {
|
||||||
store.dispatch(
|
store.dispatchNavigationAction {
|
||||||
NavigationAction.NavigateTo(
|
replaceAll(AppRoute.Welcome(intentWhichStartedActivity?.let(::SerializableIntent)))
|
||||||
screen = AppScreen.Welcome,
|
}
|
||||||
bundle = intentWhichStartedActivity?.let {
|
|
||||||
bundleOf(WelcomeFragment.INITIAL_INTENT_KEY to it)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
val toggles = store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles)
|
||||||
|
val isEnabled = toggles.isPushNotificationsEnabled && !cardRepository.isTangemTOSAccepted()
|
||||||
|
val route = if (isEnabled) AppRoute.Disclaimer(isTosAccepted = false) else AppRoute.Home
|
||||||
|
|
||||||
|
store.dispatchNavigationAction { replaceAll(route) }
|
||||||
intentProcessor.handleIntent(intentWhichStartedActivity, false)
|
intentProcessor.handleIntent(intentWhichStartedActivity, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -485,16 +549,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForNotificationPermission() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
|
||||||
BuildConfig.LOG_ENABLED &&
|
|
||||||
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) !=
|
|
||||||
PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observePolkadotAccountHealthCheck() {
|
private fun observePolkadotAccountHealthCheck() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
getPolkadotCheckHasResetUseCase()
|
getPolkadotCheckHasResetUseCase()
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import com.tangem.LogFormat
|
||||||
import com.tangem.TangemSdkLogger
|
import com.tangem.TangemSdkLogger
|
||||||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||||
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
|
||||||
|
|
@ -43,9 +44,9 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||||
import com.tangem.features.details.DetailsEntryPoint
|
|
||||||
import com.tangem.features.details.DetailsFeatureToggles
|
import com.tangem.features.details.DetailsFeatureToggles
|
||||||
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
|
||||||
|
import com.tangem.features.pushnotifications.api.featuretoggles.PushNotificationsFeatureToggles
|
||||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||||
|
|
@ -53,7 +54,7 @@ import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHand
|
||||||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||||
import com.tangem.tap.common.chat.ChatManager
|
import com.tangem.tap.common.chat.ChatManager
|
||||||
import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
|
import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
|
||||||
import com.tangem.tap.common.feedback.FeedbackManager
|
import com.tangem.tap.common.feedback.LegacyFeedbackManager
|
||||||
import com.tangem.tap.common.images.createCoilImageLoader
|
import com.tangem.tap.common.images.createCoilImageLoader
|
||||||
import com.tangem.tap.common.log.TangemLogCollector
|
import com.tangem.tap.common.log.TangemLogCollector
|
||||||
import com.tangem.tap.common.log.TimberFormatStrategy
|
import com.tangem.tap.common.log.TimberFormatStrategy
|
||||||
|
|
@ -181,13 +182,22 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
|
|
||||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase
|
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase
|
||||||
get() = entryPoint.getSaveBlockchainErrorUseCase()
|
get() = entryPoint.getSaveBlockchainErrorUseCase()
|
||||||
// endregion
|
|
||||||
|
|
||||||
private val detailsFeatureToggles: DetailsFeatureToggles
|
private val detailsFeatureToggles: DetailsFeatureToggles
|
||||||
get() = entryPoint.getDetailsFeatureToggles()
|
get() = entryPoint.getDetailsFeatureToggles()
|
||||||
|
|
||||||
private val detailsEntryPoint: DetailsEntryPoint
|
private val urlOpener
|
||||||
get() = entryPoint.getDetailsEntryPoint()
|
get() = entryPoint.getUrlOpener()
|
||||||
|
|
||||||
|
private val shareManager
|
||||||
|
get() = entryPoint.getShareManager()
|
||||||
|
|
||||||
|
private val appRouter: AppRouter
|
||||||
|
get() = entryPoint.getAppRouter()
|
||||||
|
|
||||||
|
private val pushNotificationsFeatureToggles: PushNotificationsFeatureToggles
|
||||||
|
get() = entryPoint.getPushNotificationsFeatureToggles()
|
||||||
|
// endregion
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
@ -275,7 +285,10 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
blockchainSDKFactory = blockchainSDKFactory,
|
blockchainSDKFactory = blockchainSDKFactory,
|
||||||
saveBlockchainErrorUseCase = saveBlockchainErrorUseCase,
|
saveBlockchainErrorUseCase = saveBlockchainErrorUseCase,
|
||||||
detailsFeatureToggles = detailsFeatureToggles,
|
detailsFeatureToggles = detailsFeatureToggles,
|
||||||
detailsEntryPoint = detailsEntryPoint,
|
urlOpener = urlOpener,
|
||||||
|
shareManager = shareManager,
|
||||||
|
appRouter = appRouter,
|
||||||
|
pushNotificationsFeatureToggles = pushNotificationsFeatureToggles,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -363,7 +376,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
logger = if (feedbackManagerFeatureToggles.isLocalLogsEnabled) tangemSdkLogger else tangemLogCollector,
|
logger = if (feedbackManagerFeatureToggles.isLocalLogsEnabled) tangemSdkLogger else tangemLogCollector,
|
||||||
)
|
)
|
||||||
|
|
||||||
val feedbackManager = FeedbackManager(
|
val feedbackManager = LegacyFeedbackManager(
|
||||||
infoHolder = additionalFeedbackInfo,
|
infoHolder = additionalFeedbackInfo,
|
||||||
logCollector = tangemLogCollector,
|
logCollector = tangemLogCollector,
|
||||||
chatManager = ChatManager(foregroundActivityObserver),
|
chatManager = ChatManager(foregroundActivityObserver),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.common
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.tangem.core.navigation.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.tap.common.redux.AppDialog
|
import com.tangem.tap.common.redux.AppDialog
|
||||||
import com.tangem.tap.common.redux.global.GlobalState
|
import com.tangem.tap.common.redux.global.GlobalState
|
||||||
import com.tangem.tap.common.ui.*
|
import com.tangem.tap.common.ui.*
|
||||||
|
|
@ -46,7 +46,11 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
||||||
|
|
||||||
dialog = when (state.dialog) {
|
dialog = when (state.dialog) {
|
||||||
is AppDialog.SimpleOkDialogRes -> SimpleOkDialog.create(state.dialog, context)
|
is AppDialog.SimpleOkDialogRes -> SimpleOkDialog.create(state.dialog, context)
|
||||||
is StateDialog.ScanFailsDialog -> ScanFailsDialog.create(context, state.dialog.source)
|
is StateDialog.ScanFailsDialog -> ScanFailsDialog.create(
|
||||||
|
context = context,
|
||||||
|
source = state.dialog.source,
|
||||||
|
onTryAgain = state.dialog.onTryAgain,
|
||||||
|
)
|
||||||
is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context)
|
is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context)
|
||||||
is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context)
|
is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context)
|
||||||
is AppDialog.RussianCardholdersWarningDialog -> RussianCardholdersWarningBottomSheetDialog(
|
is AppDialog.RussianCardholdersWarningDialog -> RussianCardholdersWarningBottomSheetDialog(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.tangem.tap.common.analytics.events
|
||||||
|
|
||||||
|
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
|
|
||||||
|
class ScanFailsDialogAnalytics(button: Buttons, source: AnalyticsParam.ScreensSources) : AnalyticsEvent(
|
||||||
|
category = "Cant Scan The Card",
|
||||||
|
event = button.event,
|
||||||
|
params = mapOf(
|
||||||
|
AnalyticsParam.SOURCE to source.value,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
enum class Buttons(val event: String) {
|
||||||
|
TRY_AGAIN("Try again button"),
|
||||||
|
HOW_TO_SCAN("Button blog"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,171 +1,51 @@
|
||||||
package com.tangem.tap.common.extensions
|
package com.tangem.tap.common.extensions
|
||||||
|
|
||||||
import android.os.Bundle
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.*
|
import androidx.fragment.app.Fragment
|
||||||
import com.tangem.core.navigation.AppScreen
|
import androidx.fragment.app.FragmentManager
|
||||||
import com.tangem.core.navigation.FragmentShareTransition
|
import com.tangem.utils.Provider
|
||||||
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 com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
fun FragmentActivity.openFragment(
|
fun FragmentManager.showFragmentAllowingStateLoss(name: String, fragmentProvider: Provider<Fragment>) {
|
||||||
screen: AppScreen,
|
Timber.d("Showing $name route")
|
||||||
addToBackstack: Boolean,
|
|
||||||
bundle: Bundle? = null,
|
|
||||||
fgShareTransition: FragmentShareTransition? = null,
|
|
||||||
) {
|
|
||||||
val transaction = supportFragmentManager.beginTransaction().apply {
|
|
||||||
setReorderingAllowed(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val fragment = fragmentFactory(screen).apply {
|
val isPoppedBack = popBackStackImmediate(name, 0)
|
||||||
arguments = bundle
|
|
||||||
|
|
||||||
if (fgShareTransition != null) {
|
if (!isPoppedBack) {
|
||||||
sharedElementEnterTransition = fgShareTransition.enterTransitionSet
|
val fragment = fragmentProvider()
|
||||||
sharedElementReturnTransition = fgShareTransition.exitTransitionSet
|
|
||||||
fgShareTransition.shareElements.forEach { shareElement ->
|
if (fragment is DialogFragment) {
|
||||||
shareElement.wView.get()?.let { view ->
|
fragment.showDialog(fragmentManager = this, name)
|
||||||
transaction.addSharedElement(view, shareElement.elementName)
|
} else {
|
||||||
}
|
fragment.showFragment(fragmentManager = this, name)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (screen.isDialogFragment && fragment is DialogFragment) {
|
Timber.d("Route $name is shown")
|
||||||
fragment.showAllowingStateLoss(
|
|
||||||
fragmentManager = supportFragmentManager,
|
|
||||||
baseTransaction = transaction,
|
|
||||||
tag = screen.name,
|
|
||||||
addToBackstack = addToBackstack,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
transaction.replace(R.id.fragment_container, fragment, screen.name)
|
Timber.d("Route $name is found in backstack and shown")
|
||||||
if (addToBackstack) {
|
}
|
||||||
transaction.addToBackStack(screen.name)
|
}
|
||||||
}
|
|
||||||
|
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()
|
transaction.commitAllowingStateLoss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DialogFragment.showAllowingStateLoss(
|
private fun Fragment.showFragment(fragmentManager: FragmentManager, name: String) {
|
||||||
fragmentManager: FragmentManager,
|
val transaction = fragmentManager.beginTransaction()
|
||||||
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)
|
|
||||||
|
|
||||||
transaction.commitAllowingStateLoss()
|
transaction.replace(R.id.fragment_container, this, name)
|
||||||
} else {
|
transaction.addToBackStack(name)
|
||||||
Timber.e(throwable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) {
|
transaction.commitAllowingStateLoss()
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.tap.common.extensions
|
package com.tangem.tap.common.extensions
|
||||||
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
|
|
@ -82,12 +82,16 @@ suspend fun dispatchOnMain(vararg actions: Action) {
|
||||||
withMainContext { actions.forEach { store.dispatch(it) } }
|
withMainContext { actions.forEach { store.dispatch(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Store<*>.dispatchOpenUrl(url: String) {
|
fun Store<AppState>.dispatchOpenUrl(url: String) {
|
||||||
dispatch(NavigationAction.OpenUrl(url))
|
inject(DaggerGraphState::urlOpener).openUrl(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Store<*>.dispatchShare(url: String) {
|
fun Store<AppState>.dispatchShare(url: String) {
|
||||||
dispatch(NavigationAction.Share(url))
|
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 {
|
inline fun <reified T> Store<AppState>.inject(getDependency: DaggerGraphState.() -> T?): T {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@
|
||||||
package com.tangem.tap.common.extensions
|
package com.tangem.tap.common.extensions
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.*
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.*
|
import androidx.annotation.*
|
||||||
|
|
@ -78,16 +81,6 @@ fun Context.getFromClipboard(default: CharSequence? = null): CharSequence? {
|
||||||
return clipData.getItemAt(0).text
|
return clipData.getItemAt(0).text
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.shareText(text: String) {
|
|
||||||
val sendIntent: Intent = Intent().apply {
|
|
||||||
action = Intent.ACTION_SEND
|
|
||||||
putExtra(Intent.EXTRA_TEXT, text)
|
|
||||||
type = "text/plain"
|
|
||||||
}
|
|
||||||
val shareIntent = Intent.createChooser(sendIntent, null)
|
|
||||||
startActivity(shareIntent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
|
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
|
||||||
return context.getString(resId, *formatArgs)
|
return context.getString(resId, *formatArgs)
|
||||||
}
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ import java.io.StringWriter
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
class FeedbackManager(
|
class LegacyFeedbackManager(
|
||||||
val infoHolder: AdditionalFeedbackInfo,
|
val infoHolder: AdditionalFeedbackInfo,
|
||||||
private val logCollector: TangemLogCollector,
|
private val logCollector: TangemLogCollector,
|
||||||
private val chatManager: ChatManager,
|
private val chatManager: ChatManager,
|
||||||
|
|
@ -144,7 +144,7 @@ class FeedbackManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
private companion object {
|
||||||
const val DEFAULT_SUPPORT_EMAIL = "support@tangem.com"
|
const val DEFAULT_SUPPORT_EMAIL = "support@tangem.com"
|
||||||
const val S2C_SUPPORT_EMAIL = "cardsupport@start2coin.com"
|
const val S2C_SUPPORT_EMAIL = "cardsupport@start2coin.com"
|
||||||
const val FEEDBACK_FILE = "feedback.txt"
|
const val FEEDBACK_FILE = "feedback.txt"
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.tangem.tap.common.feedback
|
||||||
|
|
||||||
|
import com.tangem.core.navigation.feedback.FeedbackManager
|
||||||
|
import com.tangem.core.navigation.feedback.FeedbackType
|
||||||
|
import com.tangem.tap.store
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
internal class ProxyFeedbackManager : FeedbackManager {
|
||||||
|
|
||||||
|
override fun sendEmail(type: FeedbackType) {
|
||||||
|
val manager = store.state.globalState.feedbackManager
|
||||||
|
|
||||||
|
if (manager == null) {
|
||||||
|
Timber.e("Feedback manager is not initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val data = when (type) {
|
||||||
|
is FeedbackType.Feedback -> FeedbackEmail()
|
||||||
|
is FeedbackType.RateCanBeBetter -> RateCanBeBetterEmail()
|
||||||
|
is FeedbackType.ScanFails -> ScanFailsEmail()
|
||||||
|
is FeedbackType.SendTransactionFailed -> SendTransactionFailedEmail(type.error)
|
||||||
|
is FeedbackType.Support -> FeedbackEmail()
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.sendEmail(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.tangem.tap.common.finisher
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import com.tangem.core.navigation.finisher.AppFinisher
|
||||||
|
import com.tangem.tap.MainActivity
|
||||||
|
import com.tangem.tap.foregroundActivityObserver
|
||||||
|
import com.tangem.tap.withForegroundActivity
|
||||||
|
|
||||||
|
internal class AndroidAppFinisher(
|
||||||
|
private val appContext: Context,
|
||||||
|
) : AppFinisher {
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
foregroundActivityObserver.withForegroundActivity { activity ->
|
||||||
|
activity.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun restart() {
|
||||||
|
val intent = Intent(appContext, MainActivity::class.java).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
}
|
||||||
|
appContext.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.tangem.tap.common.pushes
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import coil.executeBlocking
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
|
import com.tangem.domain.common.LogConfig
|
||||||
|
import com.tangem.tap.MainActivity
|
||||||
|
import com.tangem.tap.common.images.createCoilImageLoader
|
||||||
|
import com.tangem.wallet.R
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@SuppressLint("MissingFirebaseInstanceTokenRefresh")
|
||||||
|
internal class TangemPushNotificationService : FirebaseMessagingService() {
|
||||||
|
|
||||||
|
override fun onNewToken(token: String) {
|
||||||
|
super.onNewToken(token)
|
||||||
|
Timber.d("New FCM token received: $token")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessageReceived(message: RemoteMessage) {
|
||||||
|
super.onMessageReceived(message)
|
||||||
|
|
||||||
|
val notification = message.notification ?: return
|
||||||
|
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
||||||
|
|
||||||
|
// TODO refactoring: [REDACTED_JIRA]
|
||||||
|
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
/* context = */ this,
|
||||||
|
/* requestCode = */ PUSH_NOTIFICATION_REQUEST_CODE,
|
||||||
|
/* intent = */ intent,
|
||||||
|
/* flags = */ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
||||||
|
)
|
||||||
|
|
||||||
|
val notificationBuilder =
|
||||||
|
NotificationCompat.Builder(applicationContext, channelId)
|
||||||
|
.setSmallIcon(R.drawable.ic_tangem_24)
|
||||||
|
.setContentTitle(notification.title)
|
||||||
|
.setContentText(notification.body)
|
||||||
|
.setPriority(message.priority)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setVibrate(notification.vibrateTimings)
|
||||||
|
.apply {
|
||||||
|
notification.imageUrl?.let { uri ->
|
||||||
|
val bitmap = getBitmapImageFromUrl(uri)
|
||||||
|
setStyle(
|
||||||
|
NotificationCompat
|
||||||
|
.BigPictureStyle()
|
||||||
|
.bigPicture(bitmap),
|
||||||
|
).setLargeIcon(bitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val notificationManager = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val notificationChannel = NotificationChannel(
|
||||||
|
channelId,
|
||||||
|
ContextCompat.getString(applicationContext, R.string.tangem_app_name),
|
||||||
|
NotificationManager.IMPORTANCE_HIGH,
|
||||||
|
)
|
||||||
|
notificationManager.createNotificationChannel(notificationChannel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generating unique notification id
|
||||||
|
val uniqueId = (System.currentTimeMillis() % Integer.MAX_VALUE).toInt()
|
||||||
|
|
||||||
|
notificationManager.notify(
|
||||||
|
/* id = */ uniqueId,
|
||||||
|
/* notification = */ notificationBuilder.build(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBitmapImageFromUrl(url: Uri): Bitmap? {
|
||||||
|
return createCoilImageLoader(
|
||||||
|
applicationContext,
|
||||||
|
logEnabled = LogConfig.imageLoader,
|
||||||
|
).executeBlocking(
|
||||||
|
ImageRequest.Builder(applicationContext)
|
||||||
|
.data(url)
|
||||||
|
.build(),
|
||||||
|
).drawable?.toBitmap()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications
|
||||||
|
const val PUSH_NOTIFICATION_REQUEST_CODE = 123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.common.redux
|
package com.tangem.tap.common.redux
|
||||||
|
|
||||||
import com.tangem.common.extensions.VoidCallback
|
import com.tangem.common.extensions.VoidCallback
|
||||||
import com.tangem.core.navigation.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.tap.common.TestAction
|
import com.tangem.tap.common.TestAction
|
||||||
import com.tangem.tap.domain.model.Currency
|
import com.tangem.tap.domain.model.Currency
|
||||||
import com.tangem.tap.domain.model.WalletAddressData
|
import com.tangem.tap.domain.model.WalletAddressData
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.tap.common.redux
|
package com.tangem.tap.common.redux
|
||||||
|
|
||||||
import com.tangem.tap.common.redux.global.globalReducer
|
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.DetailsReducer
|
||||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
|
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer
|
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
|
if (action is AppAction.RestoreState) return action.state
|
||||||
|
|
||||||
return AppState(
|
return AppState(
|
||||||
navigationState = NavigationReducer.reduce(action, state),
|
|
||||||
globalState = globalReducer(action, state, appStateHolder),
|
globalState = globalReducer(action, state, appStateHolder),
|
||||||
homeState = HomeReducer.reduce(action, state),
|
homeState = HomeReducer.reduce(action, state),
|
||||||
onboardingNoteState = OnboardingNoteReducer.reduce(action, state),
|
onboardingNoteState = OnboardingNoteReducer.reduce(action, state),
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package com.tangem.tap.common.redux
|
package com.tangem.tap.common.redux
|
||||||
|
|
||||||
import com.tangem.core.navigation.NavigationState
|
|
||||||
import com.tangem.domain.redux.DomainState
|
import com.tangem.domain.redux.DomainState
|
||||||
import com.tangem.domain.redux.domainStore
|
import com.tangem.domain.redux.domainStore
|
||||||
import com.tangem.domain.redux.global.NetworkServices
|
import com.tangem.domain.redux.global.NetworkServices
|
||||||
import com.tangem.tap.common.redux.global.GlobalMiddleware
|
import com.tangem.tap.common.redux.global.GlobalMiddleware
|
||||||
import com.tangem.tap.common.redux.global.GlobalState
|
import com.tangem.tap.common.redux.global.GlobalState
|
||||||
import com.tangem.tap.common.redux.legacy.LegacyMiddleware
|
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.DetailsMiddleware
|
||||||
import com.tangem.tap.features.details.redux.DetailsState
|
import com.tangem.tap.features.details.redux.DetailsState
|
||||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware
|
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware
|
||||||
|
|
@ -40,7 +38,6 @@ import org.rekotlin.Middleware
|
||||||
import org.rekotlin.StateType
|
import org.rekotlin.StateType
|
||||||
|
|
||||||
data class AppState(
|
data class AppState(
|
||||||
val navigationState: NavigationState = NavigationState(),
|
|
||||||
val globalState: GlobalState = GlobalState(),
|
val globalState: GlobalState = GlobalState(),
|
||||||
val homeState: HomeState = HomeState(),
|
val homeState: HomeState = HomeState(),
|
||||||
val onboardingNoteState: OnboardingNoteState = OnboardingNoteState(),
|
val onboardingNoteState: OnboardingNoteState = OnboardingNoteState(),
|
||||||
|
|
@ -73,7 +70,6 @@ data class AppState(
|
||||||
fun getMiddleware(): List<Middleware<AppState>> {
|
fun getMiddleware(): List<Middleware<AppState>> {
|
||||||
return listOf(
|
return listOf(
|
||||||
logMiddleware,
|
logMiddleware,
|
||||||
navigationMiddleware,
|
|
||||||
notificationsMiddleware,
|
notificationsMiddleware,
|
||||||
GlobalMiddleware.handler,
|
GlobalMiddleware.handler,
|
||||||
HomeMiddleware.handler,
|
HomeMiddleware.handler,
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ package com.tangem.tap.common.redux.global
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.datasource.config.ConfigManager
|
import com.tangem.datasource.config.ConfigManager
|
||||||
import com.tangem.datasource.config.models.ChatConfig
|
import com.tangem.datasource.config.models.ChatConfig
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.tap.common.feedback.FeedbackData
|
import com.tangem.tap.common.feedback.FeedbackData
|
||||||
import com.tangem.tap.common.feedback.FeedbackManager
|
import com.tangem.tap.common.feedback.LegacyFeedbackManager
|
||||||
import com.tangem.tap.common.redux.DebugErrorAction
|
import com.tangem.tap.common.redux.DebugErrorAction
|
||||||
import com.tangem.tap.common.redux.ErrorAction
|
import com.tangem.tap.common.redux.ErrorAction
|
||||||
import com.tangem.tap.common.redux.NotificationAction
|
import com.tangem.tap.common.redux.NotificationAction
|
||||||
|
|
@ -79,7 +79,7 @@ sealed class GlobalAction : Action {
|
||||||
|
|
||||||
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
|
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
|
||||||
data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction()
|
data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction()
|
||||||
data class SetFeedbackManager(val feedbackManager: FeedbackManager) : GlobalAction()
|
data class SetFeedbackManager(val feedbackManager: LegacyFeedbackManager) : GlobalAction()
|
||||||
|
|
||||||
data class SendEmail(val feedbackData: FeedbackData) : GlobalAction()
|
data class SendEmail(val feedbackData: FeedbackData) : GlobalAction()
|
||||||
data class OpenChat(val feedbackData: FeedbackData, val chatConfig: ChatConfig? = null) : GlobalAction()
|
data class OpenChat(val feedbackData: FeedbackData, val chatConfig: ChatConfig? = null) : GlobalAction()
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.extensions.guard
|
import com.tangem.common.extensions.guard
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.datasource.config.models.Config
|
import com.tangem.datasource.config.models.Config
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.common.LogConfig
|
import com.tangem.domain.common.LogConfig
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.tap.common.extensions.*
|
import com.tangem.tap.common.extensions.*
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.features.send.redux.SendAction
|
import com.tangem.tap.features.send.redux.SendAction
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package com.tangem.tap.common.redux.global
|
package com.tangem.tap.common.redux.global
|
||||||
|
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.datasource.config.ConfigManager
|
import com.tangem.datasource.config.ConfigManager
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.tap.common.feedback.FeedbackManager
|
import com.tangem.domain.redux.StateDialog
|
||||||
|
import com.tangem.tap.common.feedback.LegacyFeedbackManager
|
||||||
import com.tangem.tap.domain.TapWalletManager
|
import com.tangem.tap.domain.TapWalletManager
|
||||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||||
import com.tangem.tap.features.onboarding.OnboardingManager
|
import com.tangem.tap.features.onboarding.OnboardingManager
|
||||||
|
|
@ -20,7 +20,7 @@ data class GlobalState(
|
||||||
val tapWalletManager: TapWalletManager = TapWalletManager(),
|
val tapWalletManager: TapWalletManager = TapWalletManager(),
|
||||||
val configManager: ConfigManager? = null,
|
val configManager: ConfigManager? = null,
|
||||||
val warningManager: WarningMessagesManager? = null,
|
val warningManager: WarningMessagesManager? = null,
|
||||||
val feedbackManager: FeedbackManager? = null,
|
val feedbackManager: LegacyFeedbackManager? = null,
|
||||||
val appCurrency: AppCurrency = AppCurrency.Default,
|
val appCurrency: AppCurrency = AppCurrency.Default,
|
||||||
val scanCardFailsCounter: Int = 0,
|
val scanCardFailsCounter: Int = 0,
|
||||||
val dialog: StateDialog? = null,
|
val dialog: StateDialog? = null,
|
||||||
|
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
package com.tangem.tap.common.redux.navigation
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.hardware.biometrics.BiometricManager
|
|
||||||
import android.os.Build
|
|
||||||
import android.provider.Settings
|
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.tap.activityResultCaller
|
|
||||||
import com.tangem.tap.common.CustomTabsManager
|
|
||||||
import com.tangem.tap.common.extensions.*
|
|
||||||
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.OpenUrl -> {
|
|
||||||
navState?.activity?.get()?.let {
|
|
||||||
CustomTabsManager().openUrl(action.url, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is NavigationAction.OpenDocument -> {
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
|
||||||
intent.data = action.url
|
|
||||||
navState?.activity?.get()?.startActivity(intent)
|
|
||||||
}
|
|
||||||
is NavigationAction.OpenDialog -> store.dispatchDialogShow(action.stateDialog)
|
|
||||||
is NavigationAction.OpenBiometricsSettings -> {
|
|
||||||
val settingsAction = when {
|
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
|
|
||||||
Settings.ACTION_BIOMETRIC_ENROLL
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
Settings.ACTION_SECURITY_SETTINGS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val intent = Intent(settingsAction).apply {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
putExtra(
|
|
||||||
Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
|
|
||||||
BiometricManager.Authenticators.BIOMETRIC_STRONG,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
activityResultCaller.activityResultLauncher?.launch(intent)
|
|
||||||
}
|
|
||||||
is NavigationAction.Share -> {
|
|
||||||
navState?.activity?.get()?.shareText(action.data)
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.tangem.tap.common.settings
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.Settings
|
||||||
|
import com.tangem.core.navigation.settings.SettingsManager
|
||||||
|
|
||||||
|
internal class IntentSettingsManager(val context: Context) : SettingsManager {
|
||||||
|
override fun openSettings() {
|
||||||
|
val openSettingsIntent = Intent(
|
||||||
|
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||||
|
Uri.fromParts("package", context.packageName, null),
|
||||||
|
)
|
||||||
|
context.startActivity(openSettingsIntent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.tangem.tap.common.share
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import com.tangem.core.navigation.share.ShareManager
|
||||||
|
import com.tangem.tap.foregroundActivityObserver
|
||||||
|
import com.tangem.tap.withForegroundActivity
|
||||||
|
|
||||||
|
internal class IntentShareManager : ShareManager {
|
||||||
|
|
||||||
|
override fun shareText(text: String) {
|
||||||
|
foregroundActivityObserver.withForegroundActivity { activity ->
|
||||||
|
val sendIntent: Intent = Intent().apply {
|
||||||
|
action = Intent.ACTION_SEND
|
||||||
|
putExtra(Intent.EXTRA_TEXT, text)
|
||||||
|
type = "text/plain"
|
||||||
|
}
|
||||||
|
val shareIntent = Intent.createChooser(sendIntent, null)
|
||||||
|
|
||||||
|
activity.startActivity(shareIntent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.tap.common.analytics.events.Token
|
import com.tangem.tap.common.analytics.events.Token
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogHide
|
import com.tangem.tap.common.extensions.dispatchDialogHide
|
||||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||||
|
|
@ -44,7 +43,7 @@ class RussianCardholdersWarningBottomSheetDialog(
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
binding?.btnNo?.setOnClickListener {
|
binding?.btnNo?.setOnClickListener {
|
||||||
store.dispatch(NavigationAction.OpenUrl(INSTRUCTION_URL))
|
store.dispatchOpenUrl(INSTRUCTION_URL)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,76 @@
|
||||||
package com.tangem.tap.common.ui
|
package com.tangem.tap.common.ui
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import androidx.core.view.isVisible
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.navigation.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
|
import com.tangem.tap.common.analytics.events.ScanFailsDialogAnalytics
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogHide
|
import com.tangem.tap.common.extensions.dispatchDialogHide
|
||||||
|
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||||
import com.tangem.tap.common.feedback.ScanFailsEmail
|
import com.tangem.tap.common.feedback.ScanFailsEmail
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
|
import com.tangem.tap.features.home.LocaleRegionProvider
|
||||||
|
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
object ScanFailsDialog {
|
internal object ScanFailsDialog {
|
||||||
fun create(context: Context, source: StateDialog.ScanFailsSource): AlertDialog {
|
|
||||||
return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply {
|
private const val HOW_TO_SCAN_RU_LINK = "https://tangem.com/ru/blog/post/scan-tangem-card/"
|
||||||
setTitle(context.getString(R.string.common_warning))
|
private const val HOW_TO_SCAN_LINK = "https://tangem.com/en/blog/post/scan-tangem-card/"
|
||||||
setMessage(R.string.alert_troubleshooting_scan_card_title)
|
|
||||||
setPositiveButton(R.string.alert_button_request_support) { _, _ ->
|
fun create(context: Context, source: StateDialog.ScanFailsSource, onTryAgain: (() -> Unit)? = null): AlertDialog {
|
||||||
val sourceAnalytics = when (source) {
|
return AlertDialog.Builder(context, R.style.CustomMaterialDialog).apply {
|
||||||
StateDialog.ScanFailsSource.MAIN -> AnalyticsParam.ScreensSources.Main
|
val customView = View.inflate(context, R.layout.dialog_scan_fails, null)
|
||||||
StateDialog.ScanFailsSource.SIGN_IN -> AnalyticsParam.ScreensSources.SignIn
|
val sourceAnalytics = when (source) {
|
||||||
StateDialog.ScanFailsSource.SETTINGS -> AnalyticsParam.ScreensSources.Settings
|
StateDialog.ScanFailsSource.MAIN -> AnalyticsParam.ScreensSources.Main
|
||||||
StateDialog.ScanFailsSource.INTRO -> AnalyticsParam.ScreensSources.Intro
|
StateDialog.ScanFailsSource.SIGN_IN -> AnalyticsParam.ScreensSources.SignIn
|
||||||
|
StateDialog.ScanFailsSource.SETTINGS -> AnalyticsParam.ScreensSources.Settings
|
||||||
|
StateDialog.ScanFailsSource.INTRO -> AnalyticsParam.ScreensSources.Intro
|
||||||
|
}
|
||||||
|
val tryAgainBtn: TextView? = customView.findViewById(R.id.try_again_button)
|
||||||
|
if (onTryAgain != null) {
|
||||||
|
tryAgainBtn?.isVisible = true
|
||||||
|
tryAgainBtn?.setOnClickListener {
|
||||||
|
store.dispatchDialogHide()
|
||||||
|
Analytics.send(
|
||||||
|
ScanFailsDialogAnalytics(
|
||||||
|
button = ScanFailsDialogAnalytics.Buttons.TRY_AGAIN,
|
||||||
|
source = sourceAnalytics,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
onTryAgain()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
tryAgainBtn?.isVisible = false
|
||||||
|
}
|
||||||
|
customView.findViewById<TextView>(R.id.how_to_scan_button)?.setOnClickListener {
|
||||||
|
Analytics.send(
|
||||||
|
ScanFailsDialogAnalytics(
|
||||||
|
button = ScanFailsDialogAnalytics.Buttons.HOW_TO_SCAN,
|
||||||
|
source = sourceAnalytics,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val locale = LocaleRegionProvider().getRegion()
|
||||||
|
val link = if (locale.lowercase() == RUSSIA_COUNTRY_CODE) HOW_TO_SCAN_RU_LINK else HOW_TO_SCAN_LINK
|
||||||
|
store.dispatchOpenUrl(link)
|
||||||
|
}
|
||||||
|
customView.findViewById<TextView>(R.id.request_support_button)?.setOnClickListener {
|
||||||
Analytics.send(Basic.ButtonSupport(sourceAnalytics))
|
Analytics.send(Basic.ButtonSupport(sourceAnalytics))
|
||||||
store.dispatch(GlobalAction.SendEmail(ScanFailsEmail()))
|
store.dispatch(GlobalAction.SendEmail(ScanFailsEmail()))
|
||||||
}
|
}
|
||||||
setNeutralButton(R.string.common_cancel) { _, _ -> }
|
customView.findViewById<TextView>(R.id.cancel_button)?.setOnClickListener {
|
||||||
|
store.dispatchDialogHide()
|
||||||
|
}
|
||||||
|
setView(customView)
|
||||||
setOnDismissListener { store.dispatchDialogHide() }
|
setOnDismissListener { store.dispatchDialogHide() }
|
||||||
}.create()
|
}.create()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.common
|
package com.tangem.tap.common.url
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
|
@ -8,12 +8,22 @@ import androidx.browser.customtabs.CustomTabColorSchemeParams
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
import androidx.browser.customtabs.CustomTabsIntent
|
||||||
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_DARK
|
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_DARK
|
||||||
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_LIGHT
|
import androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_LIGHT
|
||||||
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||||
import com.tangem.tap.common.extensions.getColorCompat
|
import com.tangem.tap.common.extensions.getColorCompat
|
||||||
|
import com.tangem.tap.foregroundActivityObserver
|
||||||
|
import com.tangem.tap.withForegroundActivity
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
class CustomTabsManager {
|
internal class CustomTabsUrlOpener : UrlOpener {
|
||||||
fun openUrl(url: String, context: Context) {
|
|
||||||
|
override fun openUrl(url: String) {
|
||||||
|
foregroundActivityObserver.withForegroundActivity {
|
||||||
|
openUrl(url, context = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openUrl(url: String, context: Context) {
|
||||||
if (url.isEmpty()) return
|
if (url.isEmpty()) return
|
||||||
val customTabsIntent = CustomTabsIntent.Builder()
|
val customTabsIntent = CustomTabsIntent.Builder()
|
||||||
.setDefaultColorSchemeParams(
|
.setDefaultColorSchemeParams(
|
||||||
|
|
@ -6,10 +6,8 @@ import com.tangem.domain.exchange.RampStateManager
|
||||||
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||||
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||||
import com.tangem.feature.tester.ActivityClassWrapper
|
|
||||||
import com.tangem.tap.MainActivity
|
|
||||||
import com.tangem.tap.domain.sdk.TangemSdkManager
|
|
||||||
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
||||||
|
import com.tangem.tap.domain.sdk.TangemSdkManager
|
||||||
import com.tangem.tap.network.exchangeServices.DefaultRampManager
|
import com.tangem.tap.network.exchangeServices.DefaultRampManager
|
||||||
import com.tangem.tap.proxy.AppStateHolder
|
import com.tangem.tap.proxy.AppStateHolder
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
|
@ -67,10 +65,4 @@ internal object ActivityModule {
|
||||||
): GetPolkadotCheckHasImmortalUseCase {
|
): GetPolkadotCheckHasImmortalUseCase {
|
||||||
return GetPolkadotCheckHasImmortalUseCase(polkadotAccountHealthCheckRepository)
|
return GetPolkadotCheckHasImmortalUseCase(polkadotAccountHealthCheckRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideActivityClassWrapper(): ActivityClassWrapper {
|
|
||||||
return ActivityClassWrapper(MainActivity::class.java)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.tangem.tap.di
|
package com.tangem.tap.di
|
||||||
|
|
||||||
import com.tangem.core.navigation.ReduxNavController
|
|
||||||
import com.tangem.domain.redux.ReduxStateHolder
|
import com.tangem.domain.redux.ReduxStateHolder
|
||||||
import com.tangem.tap.proxy.AppStateHolder
|
import com.tangem.tap.proxy.AppStateHolder
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
|
|
@ -13,10 +12,6 @@ import javax.inject.Singleton
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
internal interface AppStateHolderModule {
|
internal interface AppStateHolderModule {
|
||||||
|
|
||||||
@Binds
|
|
||||||
@Singleton
|
|
||||||
fun bindsNavigationStateHolder(appStateHolder: AppStateHolder): ReduxNavController
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun bindsReduxStateHolder(appStateHolder: AppStateHolder): ReduxStateHolder
|
fun bindsReduxStateHolder(appStateHolder: AppStateHolder): ReduxStateHolder
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.context.DefaultAppComponentContext
|
import com.tangem.core.decompose.context.DefaultAppComponentContext
|
||||||
import com.tangem.core.decompose.di.DecomposeComponent
|
import com.tangem.core.decompose.di.DecomposeComponent
|
||||||
import com.tangem.core.decompose.di.RootAppComponentContext
|
import com.tangem.core.decompose.di.RootAppComponentContext
|
||||||
import com.tangem.core.decompose.ui.UiMessage
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.decompose.ui.UiMessageHandler
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -16,7 +15,6 @@ import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.components.ActivityComponent
|
import dagger.hilt.android.components.ActivityComponent
|
||||||
import dagger.hilt.android.qualifiers.ActivityContext
|
import dagger.hilt.android.qualifiers.ActivityContext
|
||||||
import dagger.hilt.android.scopes.ActivityScoped
|
import dagger.hilt.android.scopes.ActivityScoped
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(ActivityComponent::class)
|
@InstallIn(ActivityComponent::class)
|
||||||
|
|
@ -29,17 +27,11 @@ internal object RootAppComponentContextModule {
|
||||||
@ActivityContext context: Context,
|
@ActivityContext context: Context,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
componentBuilder: DecomposeComponent.Builder,
|
componentBuilder: DecomposeComponent.Builder,
|
||||||
|
uiDependencies: UiDependencies,
|
||||||
): AppComponentContext {
|
): AppComponentContext {
|
||||||
// TODO: Implement message handler
|
|
||||||
val dummyMessageHandler = object : UiMessageHandler {
|
|
||||||
override fun handleMessage(message: UiMessage) {
|
|
||||||
Timber.w("Unable to handle message: $message")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return DefaultAppComponentContext(
|
return DefaultAppComponentContext(
|
||||||
componentContext = (context as AppCompatActivity).defaultComponentContext(),
|
componentContext = (context as AppCompatActivity).defaultComponentContext(),
|
||||||
messageHandler = dummyMessageHandler,
|
messageHandler = uiDependencies.eventMessageHandler,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
hiltComponentBuilder = componentBuilder,
|
hiltComponentBuilder = componentBuilder,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package com.tangem.tap.di
|
package com.tangem.tap.di
|
||||||
|
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import com.tangem.core.ui.UiDependencies
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.ui.haptic.HapticManager
|
import com.tangem.core.ui.haptic.HapticManager
|
||||||
|
import com.tangem.core.ui.message.EventMessageHandler
|
||||||
import com.tangem.core.ui.theme.AppThemeModeHolder
|
import com.tangem.core.ui.theme.AppThemeModeHolder
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -19,6 +21,8 @@ internal object UiDependenciesModule {
|
||||||
return object : UiDependencies {
|
return object : UiDependencies {
|
||||||
override val hapticManager = hapticManager
|
override val hapticManager = hapticManager
|
||||||
override val appThemeModeHolder = appThemeModeHolder
|
override val appThemeModeHolder = appThemeModeHolder
|
||||||
|
override val globalSnackbarHostState: SnackbarHostState = SnackbarHostState()
|
||||||
|
override val eventMessageHandler: EventMessageHandler = EventMessageHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
44
app/src/main/java/com/tangem/tap/di/UtilsModule.kt
Normal file
44
app/src/main/java/com/tangem/tap/di/UtilsModule.kt
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.tangem.tap.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.tangem.core.navigation.feedback.FeedbackManager
|
||||||
|
import com.tangem.core.navigation.finisher.AppFinisher
|
||||||
|
import com.tangem.core.navigation.settings.SettingsManager
|
||||||
|
import com.tangem.core.navigation.share.ShareManager
|
||||||
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
|
import com.tangem.tap.common.feedback.ProxyFeedbackManager
|
||||||
|
import com.tangem.tap.common.finisher.AndroidAppFinisher
|
||||||
|
import com.tangem.tap.common.settings.IntentSettingsManager
|
||||||
|
import com.tangem.tap.common.share.IntentShareManager
|
||||||
|
import com.tangem.tap.common.url.CustomTabsUrlOpener
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
internal object UtilsModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideShareManager(): ShareManager = IntentShareManager()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideUrlOpener(): UrlOpener = CustomTabsUrlOpener()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideFeedbackManager(): FeedbackManager = ProxyFeedbackManager()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideAppFinisher(@ApplicationContext context: Context): AppFinisher = AndroidAppFinisher(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideSettingsManager(@ApplicationContext context: Context): SettingsManager = IntentSettingsManager(context)
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
||||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||||
import com.tangem.domain.settings.*
|
import com.tangem.domain.settings.*
|
||||||
import com.tangem.domain.settings.repositories.AppRatingRepository
|
import com.tangem.domain.settings.repositories.AppRatingRepository
|
||||||
|
import com.tangem.domain.settings.repositories.PermissionRepository
|
||||||
import com.tangem.domain.settings.repositories.PromoSettingsRepository
|
import com.tangem.domain.settings.repositories.PromoSettingsRepository
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import com.tangem.tap.domain.sdk.TangemSdkManager
|
import com.tangem.tap.domain.sdk.TangemSdkManager
|
||||||
|
|
@ -17,6 +18,7 @@ import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Suppress("TooManyFunctions")
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
internal object SettingsDomainModule {
|
internal object SettingsDomainModule {
|
||||||
|
|
@ -164,4 +166,52 @@ internal object SettingsDomainModule {
|
||||||
): IncrementAppLaunchCounterUseCase {
|
): IncrementAppLaunchCounterUseCase {
|
||||||
return IncrementAppLaunchCounterUseCase(settingsRepository = settingsRepository)
|
return IncrementAppLaunchCounterUseCase(settingsRepository = settingsRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region PushPermissionRepository
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideShouldInitiallyAskPermissionUseCase(
|
||||||
|
permissionRepository: PermissionRepository,
|
||||||
|
): ShouldInitiallyAskPermissionUseCase {
|
||||||
|
return ShouldInitiallyAskPermissionUseCase(repository = permissionRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideIsFirstTimeAskingPermissionUseCase(
|
||||||
|
permissionRepository: PermissionRepository,
|
||||||
|
): IsFirstTimeAskingPermissionUseCase {
|
||||||
|
return IsFirstTimeAskingPermissionUseCase(repository = permissionRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideSetFirstTimeAskingPushPermissionUseCase(
|
||||||
|
permissionRepository: PermissionRepository,
|
||||||
|
): SetFirstTimeAskingPermissionUseCase {
|
||||||
|
return SetFirstTimeAskingPermissionUseCase(repository = permissionRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDelayPermissionRequestUseCase(
|
||||||
|
permissionRepository: PermissionRepository,
|
||||||
|
): DelayPermissionRequestUseCase {
|
||||||
|
return DelayPermissionRequestUseCase(repository = permissionRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideShouldAskPermissionUseCase(permissionRepository: PermissionRepository): ShouldAskPermissionUseCase {
|
||||||
|
return ShouldAskPermissionUseCase(repository = permissionRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideNeverRequestPermissionUseCase(
|
||||||
|
permissionRepository: PermissionRepository,
|
||||||
|
): NeverRequestPermissionUseCase {
|
||||||
|
return NeverRequestPermissionUseCase(repository = permissionRepository)
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,8 @@ package com.tangem.tap.di.domain
|
||||||
import com.tangem.domain.settings.*
|
import com.tangem.domain.settings.*
|
||||||
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
||||||
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
|
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
|
||||||
|
import com.tangem.domain.staking.FetchStakingTokensUseCase
|
||||||
|
import com.tangem.domain.staking.GetYieldUseCase
|
||||||
import com.tangem.domain.staking.repositories.StakingRepository
|
import com.tangem.domain.staking.repositories.StakingRepository
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -14,6 +16,14 @@ import javax.inject.Singleton
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
internal object StakingDomainModule {
|
internal object StakingDomainModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetStakingAvailabilityUseCase(stakingRepository: StakingRepository): GetStakingAvailabilityUseCase {
|
||||||
|
return GetStakingAvailabilityUseCase(
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetStakingEntryInfoUseCase(stakingRepository: StakingRepository): GetStakingEntryInfoUseCase {
|
fun provideGetStakingEntryInfoUseCase(stakingRepository: StakingRepository): GetStakingEntryInfoUseCase {
|
||||||
|
|
@ -24,8 +34,16 @@ internal object StakingDomainModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetStakingAvailabilityUseCase(stakingRepository: StakingRepository): GetStakingAvailabilityUseCase {
|
fun provideGetYieldUseCase(stakingRepository: StakingRepository): GetYieldUseCase {
|
||||||
return GetStakingAvailabilityUseCase(
|
return GetYieldUseCase(
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetStakingTokensUseCase(stakingRepository: StakingRepository): FetchStakingTokensUseCase {
|
||||||
|
return FetchStakingTokensUseCase(
|
||||||
stakingRepository = stakingRepository,
|
stakingRepository = stakingRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.domain.exchange.RampStateManager
|
import com.tangem.domain.exchange.RampStateManager
|
||||||
import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
|
import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
|
||||||
|
import com.tangem.domain.staking.repositories.StakingRepository
|
||||||
import com.tangem.domain.tokens.*
|
import com.tangem.domain.tokens.*
|
||||||
import com.tangem.domain.tokens.repository.*
|
import com.tangem.domain.tokens.repository.*
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
|
|
@ -190,6 +191,7 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetCryptoCurrencyActionsUseCase {
|
): GetCryptoCurrencyActionsUseCase {
|
||||||
return GetCryptoCurrencyActionsUseCase(
|
return GetCryptoCurrencyActionsUseCase(
|
||||||
|
|
@ -199,6 +201,7 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
quotesRepository = quotesRepository,
|
quotesRepository = quotesRepository,
|
||||||
networksRepository = networksRepository,
|
networksRepository = networksRepository,
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,12 @@ internal object TransactionDomainModule {
|
||||||
return CreateTransactionUseCase(transactionRepository)
|
return CreateTransactionUseCase(transactionRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideEstimateFeeUseCase(walletManagersFacade: WalletManagersFacade): EstimateFeeUseCase {
|
||||||
|
return EstimateFeeUseCase(walletManagersFacade)
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideIsFeeApproximateUseCase(feeRepository: FeeRepository): IsFeeApproximateUseCase {
|
fun provideIsFeeApproximateUseCase(feeRepository: FeeRepository): IsFeeApproximateUseCase {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
package com.tangem.tap.domain.card
|
package com.tangem.tap.domain.card
|
||||||
|
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
|
import com.tangem.common.card.EllipticCurve
|
||||||
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.doOnFailure
|
import com.tangem.common.doOnFailure
|
||||||
import com.tangem.common.doOnSuccess
|
import com.tangem.common.doOnSuccess
|
||||||
import com.tangem.common.extensions.ByteArrayKey
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
|
import com.tangem.common.extensions.toMapKey
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
import com.tangem.domain.card.repository.DerivationsRepository
|
||||||
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
|
|
@ -45,7 +49,10 @@ internal class DefaultDerivationsRepository(
|
||||||
tangemSdkManager.derivePublicKeys(cardId = null, derivations = derivations)
|
tangemSdkManager.derivePublicKeys(cardId = null, derivations = derivations)
|
||||||
.doOnSuccess { response ->
|
.doOnSuccess { response ->
|
||||||
updatePublicKeys(userWalletId = userWalletId, keys = response.entries).fold(
|
updatePublicKeys(userWalletId = userWalletId, keys = response.entries).fold(
|
||||||
onSuccess = { return },
|
onSuccess = {
|
||||||
|
validateDerivations(userWallet.scanResponse, derivations)
|
||||||
|
return
|
||||||
|
},
|
||||||
onFailure = { throw it },
|
onFailure = { throw it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +83,22 @@ internal class DefaultDerivationsRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It throws an exception if any of the provided derivations are invalid
|
||||||
|
* Validation for NonHardened moved to application layer, to avoid fails when derive multiple paths
|
||||||
|
* It needs to be called after success [derivePublicKeys] or in same flows
|
||||||
|
*/
|
||||||
|
private fun validateDerivations(scanResponse: ScanResponse, derivations: Derivations) {
|
||||||
|
derivations.entries.forEach { derivationForKey ->
|
||||||
|
val wallet = scanResponse.card.wallets.firstOrNull { it.publicKey.toMapKey() == derivationForKey.key }
|
||||||
|
if (wallet == null) return@forEach
|
||||||
|
val hasHardenedNodes = derivationForKey.value.any { path -> path.nodes.any { node -> !node.isHardened } }
|
||||||
|
if (wallet.curve == EllipticCurve.Ed25519Slip0010 && hasHardenedNodes) {
|
||||||
|
throw TangemSdkError.NonHardenedDerivationNotSupported()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun updatePublicKeys(userWalletId: UserWalletId, keys: DerivedKeys): Result<Unit> {
|
private suspend fun updatePublicKeys(userWalletId: UserWalletId, keys: DerivedKeys): Result<Unit> {
|
||||||
return runCatching(dispatchers.io) {
|
return runCatching(dispatchers.io) {
|
||||||
userWalletsStore.update(
|
userWalletsStore.update(
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,11 @@ import com.tangem.common.core.TangemError
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.doOnFailure
|
import com.tangem.common.doOnFailure
|
||||||
import com.tangem.common.doOnSuccess
|
import com.tangem.common.doOnSuccess
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
import com.tangem.domain.common.util.twinsIsTwinned
|
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.createDisclaimer
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
|
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.OnboardingHelper
|
||||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
||||||
|
|
@ -118,7 +118,7 @@ internal object LegacyScanProcessor {
|
||||||
disclaimerWillShow()
|
disclaimerWillShow()
|
||||||
store.dispatchWithMain(
|
store.dispatchWithMain(
|
||||||
DisclaimerAction.Show(
|
DisclaimerAction.Show(
|
||||||
fromScreen = AppScreen.Home,
|
from = DisclaimerSource.Home,
|
||||||
callback = DisclaimerCallback(
|
callback = DisclaimerCallback(
|
||||||
onAccept = {
|
onAccept = {
|
||||||
scope.launch(Dispatchers.Main) {
|
scope.launch(Dispatchers.Main) {
|
||||||
|
|
@ -170,7 +170,7 @@ internal object LegacyScanProcessor {
|
||||||
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
||||||
onWalletNotCreated()
|
onWalletNotCreated()
|
||||||
store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse)))
|
store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse)))
|
||||||
navigateTo(AppScreen.OnboardingTwins) { onProgressStateChange(it) }
|
navigateTo(AppRoute.OnboardingTwins) { onProgressStateChange(it) }
|
||||||
} else {
|
} else {
|
||||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||||
onSuccess(scanResponse)
|
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)
|
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(screen))
|
store.dispatchNavigationAction { push(route) }
|
||||||
onProgressStateChange(false)
|
onProgressStateChange(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,16 +3,15 @@ package com.tangem.tap.domain.scanCard
|
||||||
import arrow.fx.coroutines.resourceScope
|
import arrow.fx.coroutines.resourceScope
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.core.TangemError
|
import com.tangem.common.core.TangemError
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.domain.card.ScanCardException
|
import com.tangem.domain.card.ScanCardException
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
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.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.common.extensions.inject
|
||||||
import com.tangem.tap.domain.scanCard.chains.*
|
import com.tangem.tap.domain.scanCard.chains.*
|
||||||
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
||||||
|
|
@ -60,7 +59,11 @@ internal object UseCaseScanProcessor {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
||||||
add(DisclaimerChain(store, disclaimerWillShow))
|
val pushNotificationsToggles =
|
||||||
|
store.inject(getDependency = DaggerGraphState::pushNotificationsFeatureToggles)
|
||||||
|
if (pushNotificationsToggles.isPushNotificationsEnabled) {
|
||||||
|
add(DisclaimerChain(store, disclaimerWillShow))
|
||||||
|
}
|
||||||
add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager))
|
add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,8 +135,8 @@ internal object UseCaseScanProcessor {
|
||||||
action()
|
action()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun navigateTo(screen: AppScreen) {
|
private suspend inline fun navigateTo(route: AppRoute) {
|
||||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
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.left
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.domain.card.ScanCardException
|
import com.tangem.domain.card.ScanCardException
|
||||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||||
import com.tangem.domain.common.util.twinsIsTwinned
|
import com.tangem.domain.common.util.twinsIsTwinned
|
||||||
|
|
@ -55,8 +55,8 @@ class CheckForOnboardingChain(
|
||||||
canSkipBackup = previousChainResult.card.canSkipBackup,
|
canSkipBackup = previousChainResult.card.canSkipBackup,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
val appScreen = OnboardingHelper.whereToNavigate(previousChainResult)
|
val route = OnboardingHelper.whereToNavigate(previousChainResult)
|
||||||
ScanChainException.OnboardingNeeded(appScreen).left()
|
ScanChainException.OnboardingNeeded(route).left()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Analytics.setContext(previousChainResult)
|
Analytics.setContext(previousChainResult)
|
||||||
|
|
@ -69,7 +69,7 @@ class CheckForOnboardingChain(
|
||||||
store.dispatchOnMain(
|
store.dispatchOnMain(
|
||||||
TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(previousChainResult)),
|
TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(previousChainResult)),
|
||||||
)
|
)
|
||||||
ScanChainException.OnboardingNeeded(AppScreen.OnboardingTwins).left()
|
ScanChainException.OnboardingNeeded(AppRoute.OnboardingTwins).left()
|
||||||
} else {
|
} else {
|
||||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||||
previousChainResult.right()
|
previousChainResult.right()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package com.tangem.tap.domain.scanCard.chains
|
||||||
|
|
||||||
import arrow.core.left
|
import arrow.core.left
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.domain.card.ScanCardException
|
import com.tangem.domain.card.ScanCardException
|
||||||
import com.tangem.domain.core.chain.Chain
|
import com.tangem.domain.core.chain.Chain
|
||||||
import com.tangem.domain.core.chain.ResultChain
|
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.createDisclaimer
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
|
import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
|
||||||
|
import com.tangem.tap.features.disclaimer.redux.DisclaimerSource
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import org.rekotlin.Store
|
import org.rekotlin.Store
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
|
@ -50,7 +50,7 @@ internal class DisclaimerChain(
|
||||||
return suspendCancellableCoroutine { continuation ->
|
return suspendCancellableCoroutine { continuation ->
|
||||||
store.dispatchOnMain(
|
store.dispatchOnMain(
|
||||||
DisclaimerAction.Show(
|
DisclaimerAction.Show(
|
||||||
fromScreen = AppScreen.Home,
|
from = DisclaimerSource.Home,
|
||||||
callback = DisclaimerCallback(
|
callback = DisclaimerCallback(
|
||||||
onAccept = {
|
onAccept = {
|
||||||
if (continuation.isActive) {
|
if (continuation.isActive) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.tap.domain.scanCard.chains
|
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
|
import com.tangem.domain.card.ScanCardException
|
||||||
|
|
||||||
sealed class ScanChainException : ScanCardException.ChainException() {
|
sealed class ScanChainException : ScanCardException.ChainException() {
|
||||||
|
|
@ -19,5 +19,5 @@ sealed class ScanChainException : ScanCardException.ChainException() {
|
||||||
*
|
*
|
||||||
* @param onboardingRoute route where to navigate
|
* @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 androidx.transition.TransitionInflater
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.tangem.common.extensions.VoidCallback
|
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.tap.store
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
|
|
@ -36,7 +37,7 @@ abstract class BaseFragment(layoutId: Int) : Fragment(layoutId), FragmentOnBackP
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package com.tangem.tap.features.customtoken.impl.presentation
|
package com.tangem.tap.features.customtoken.impl.presentation
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.systemBarsPadding
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import com.tangem.core.ui.UiDependencies
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.ui.components.SystemBarsEffect
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import com.tangem.tap.features.customtoken.impl.presentation.ui.AddCustomTokenScreen
|
import com.tangem.tap.features.customtoken.impl.presentation.ui.AddCustomTokenScreen
|
||||||
|
|
@ -30,12 +30,10 @@ internal class AddCustomTokenFragment : ComposeFragment() {
|
||||||
val viewModel = hiltViewModel<AddCustomTokenViewModel>().apply {
|
val viewModel = hiltViewModel<AddCustomTokenViewModel>().apply {
|
||||||
LocalLifecycleOwner.current.lifecycle.addObserver(this)
|
LocalLifecycleOwner.current.lifecycle.addObserver(this)
|
||||||
}
|
}
|
||||||
val statusBarColor = TangemTheme.colors.background.secondary
|
|
||||||
SystemBarsEffect {
|
|
||||||
setSystemBarsColor(color = statusBarColor)
|
|
||||||
}
|
|
||||||
AddCustomTokenScreen(
|
AddCustomTokenScreen(
|
||||||
modifier = Modifier.systemBarsPadding(),
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors.background.primary)
|
||||||
|
.systemBarsPadding(),
|
||||||
stateHolder = viewModel.uiState,
|
stateHolder = viewModel.uiState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package com.tangem.tap.features.customtoken.impl.presentation.routers
|
package com.tangem.tap.features.customtoken.impl.presentation.routers
|
||||||
|
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
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.dispatchDialogShow
|
||||||
|
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||||
import com.tangem.tap.common.redux.AppDialog
|
import com.tangem.tap.common.redux.AppDialog
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
@ -12,11 +14,11 @@ import com.tangem.wallet.R
|
||||||
internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
||||||
|
|
||||||
override fun popBackStack() {
|
override fun popBackStack() {
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openWalletScreen() {
|
override fun openWalletScreen() {
|
||||||
store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openUnsupportedNetworkAlert(blockchain: Blockchain) {
|
override fun openUnsupportedNetworkAlert(blockchain: Blockchain) {
|
||||||
|
|
@ -32,7 +34,7 @@ internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
||||||
val alert = AppDialog.SimpleOkDialogRes(
|
val alert = AppDialog.SimpleOkDialogRes(
|
||||||
headerId = R.string.common_error,
|
headerId = R.string.common_error,
|
||||||
messageId = R.string.common_unknown_error,
|
messageId = R.string.common_unknown_error,
|
||||||
onOk = { store.dispatch(NavigationAction.PopBackTo()) },
|
onOk = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||||
)
|
)
|
||||||
store.dispatchDialogShow(alert)
|
store.dispatchDialogShow(alert)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ sealed class DetailsAction : Action {
|
||||||
data class ChangeAppCurrency(
|
data class ChangeAppCurrency(
|
||||||
val currency: AppCurrency,
|
val currency: AppCurrency,
|
||||||
) : AppSettings()
|
) : AppSettings()
|
||||||
|
|
||||||
|
data class Prepare(val state: AppSettingsState) : AppSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ChangeAppCurrency(val currency: AppCurrency) : DetailsAction()
|
data class ChangeAppCurrency(val currency: AppCurrency) : DetailsAction()
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ import com.tangem.common.*
|
||||||
import com.tangem.common.core.TangemError
|
import com.tangem.common.core.TangemError
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.core.UserCodeRequestPolicy
|
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.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.TextReference
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
|
|
@ -20,6 +22,7 @@ import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||||
import com.tangem.domain.wallets.legacy.asLockable
|
import com.tangem.domain.wallets.legacy.asLockable
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
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.AnalyticsParam
|
||||||
import com.tangem.tap.common.analytics.events.Settings
|
import com.tangem.tap.common.analytics.events.Settings
|
||||||
import com.tangem.tap.common.extensions.*
|
import com.tangem.tap.common.extensions.*
|
||||||
|
|
@ -30,9 +33,6 @@ import com.tangem.tap.features.demo.DemoHelper
|
||||||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
import com.tangem.tap.scope
|
|
||||||
import com.tangem.tap.store
|
|
||||||
import com.tangem.tap.tangemSdkManager
|
|
||||||
import com.tangem.utils.coroutines.JobHolder
|
import com.tangem.utils.coroutines.JobHolder
|
||||||
import com.tangem.utils.coroutines.saveIn
|
import com.tangem.utils.coroutines.saveIn
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
@ -72,7 +72,8 @@ class DetailsMiddleware {
|
||||||
is DetailsAction.AppSettings -> appSettingsMiddleware.handle(state, action)
|
is DetailsAction.AppSettings -> appSettingsMiddleware.handle(state, action)
|
||||||
is DetailsAction.ReCreateTwinsWallet -> {
|
is DetailsAction.ReCreateTwinsWallet -> {
|
||||||
store.dispatch(TwinCardsAction.SetMode(CreateTwinWalletMode.RecreateWallet))
|
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.AccessCodeRecovery -> accessCodeRecoveryMiddleware.handle(state, action)
|
||||||
is DetailsAction.ScanCard -> scanCard(state)
|
is DetailsAction.ScanCard -> scanCard(state)
|
||||||
|
|
@ -92,7 +93,7 @@ class DetailsMiddleware {
|
||||||
store.dispatch(DetailsAction.ReCreateTwinsWallet)
|
store.dispatch(DetailsAction.ReCreateTwinsWallet)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.ResetToFactory))
|
store.dispatchNavigationAction { push(AppRoute.ResetToFactory) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is DetailsAction.ResetToFactory.Proceed -> {
|
is DetailsAction.ResetToFactory.Proceed -> {
|
||||||
|
|
@ -133,15 +134,15 @@ class DetailsMiddleware {
|
||||||
|
|
||||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync
|
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync
|
||||||
if (selectedUserWallet != null) {
|
if (selectedUserWallet != null) {
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
store.onUserWalletSelected(selectedUserWallet)
|
store.onUserWalletSelected(selectedUserWallet)
|
||||||
} else {
|
} else {
|
||||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
||||||
.fold(onSuccess = { true }, onFailure = { false })
|
.fold(onSuccess = { true }, onFailure = { false })
|
||||||
if (isLocked && userWalletsListManager.hasUserWallets) {
|
if (isLocked && userWalletsListManager.hasUserWallets) {
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome))
|
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||||
} else {
|
} else {
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home))
|
store.dispatchNavigationAction { replaceAll(AppRoute.Home) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +166,7 @@ class DetailsMiddleware {
|
||||||
fun handle(action: DetailsAction.ManageSecurity, detailsState: DetailsState) {
|
fun handle(action: DetailsAction.ManageSecurity, detailsState: DetailsState) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is DetailsAction.ManageSecurity.OpenSecurity -> {
|
is DetailsAction.ManageSecurity.OpenSecurity -> {
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsSecurity))
|
store.dispatchNavigationAction { push(AppRoute.DetailsSecurity) }
|
||||||
}
|
}
|
||||||
is DetailsAction.ManageSecurity.SaveChanges -> {
|
is DetailsAction.ManageSecurity.SaveChanges -> {
|
||||||
val cardSettingsState = detailsState.cardSettingsState
|
val cardSettingsState = detailsState.cardSettingsState
|
||||||
|
|
@ -184,7 +185,7 @@ class DetailsMiddleware {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue))
|
Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue))
|
||||||
store.dispatch(GlobalAction.UpdateSecurityOptions(selectedOption))
|
store.dispatch(GlobalAction.UpdateSecurityOptions(selectedOption))
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success)
|
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success)
|
||||||
}
|
}
|
||||||
is CompletionResult.Failure -> {
|
is CompletionResult.Failure -> {
|
||||||
|
|
@ -244,6 +245,7 @@ class DetailsMiddleware {
|
||||||
is DetailsAction.AppSettings.SwitchPrivacySetting.Success,
|
is DetailsAction.AppSettings.SwitchPrivacySetting.Success,
|
||||||
is DetailsAction.AppSettings.SwitchPrivacySetting.Failure,
|
is DetailsAction.AppSettings.SwitchPrivacySetting.Failure,
|
||||||
is DetailsAction.AppSettings.BiometricsStatusChanged,
|
is DetailsAction.AppSettings.BiometricsStatusChanged,
|
||||||
|
is DetailsAction.AppSettings.Prepare,
|
||||||
-> Unit
|
-> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +275,7 @@ class DetailsMiddleware {
|
||||||
|
|
||||||
private fun enrollBiometrics() {
|
private fun enrollBiometrics() {
|
||||||
Analytics.send(Settings.AppSettings.ButtonEnableBiometricAuthentication)
|
Analytics.send(Settings.AppSettings.ButtonEnableBiometricAuthentication)
|
||||||
store.dispatchOnMain(NavigationAction.OpenBiometricsSettings)
|
activityResultCaller.openSystemBiometrySettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeAppThemeMode(appThemeMode: AppThemeMode) {
|
private fun changeAppThemeMode(appThemeMode: AppThemeMode) {
|
||||||
|
|
@ -394,7 +396,7 @@ class DetailsMiddleware {
|
||||||
deleteSavedAccessCodes()
|
deleteSavedAccessCodes()
|
||||||
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false)
|
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false)
|
||||||
|
|
||||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
|
store.dispatchNavigationAction { popTo<AppRoute.Home>() }
|
||||||
|
|
||||||
return CompletionResult.Success(Unit)
|
return CompletionResult.Success(Unit)
|
||||||
}
|
}
|
||||||
|
|
@ -433,7 +435,7 @@ class DetailsMiddleware {
|
||||||
when (action) {
|
when (action) {
|
||||||
is DetailsAction.AccessCodeRecovery.Open -> {
|
is DetailsAction.AccessCodeRecovery.Open -> {
|
||||||
Analytics.send(Settings.CardSettings.AccessCodeRecoveryButton())
|
Analytics.send(Settings.CardSettings.AccessCodeRecoveryButton())
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AccessCodeRecovery))
|
store.dispatchNavigationAction { push(AppRoute.AccessCodeRecovery) }
|
||||||
}
|
}
|
||||||
is DetailsAction.AccessCodeRecovery.SaveChanges -> {
|
is DetailsAction.AccessCodeRecovery.SaveChanges -> {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|
@ -445,7 +447,7 @@ class DetailsMiddleware {
|
||||||
AnalyticsParam.AccessCodeRecoveryStatus.from(action.enabled),
|
AnalyticsParam.AccessCodeRecoveryStatus.from(action.enabled),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
store.dispatchOnMain(
|
store.dispatchOnMain(
|
||||||
DetailsAction.AccessCodeRecovery.SaveChanges.Success(action.enabled),
|
DetailsAction.AccessCodeRecovery.SaveChanges.Success(action.enabled),
|
||||||
)
|
)
|
||||||
|
|
@ -504,7 +506,7 @@ class DetailsMiddleware {
|
||||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||||
},
|
},
|
||||||
disclaimerWillShow = {
|
disclaimerWillShow = {
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
},
|
},
|
||||||
onSuccess = { scanResponse ->
|
onSuccess = { scanResponse ->
|
||||||
createUserWallet(scanResponse)
|
createUserWallet(scanResponse)
|
||||||
|
|
@ -548,7 +550,7 @@ class DetailsMiddleware {
|
||||||
store.onUserWalletSelected(userWallet)
|
store.onUserWalletSelected(userWallet)
|
||||||
|
|
||||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
}
|
}
|
||||||
.doOnFailure { error ->
|
.doOnFailure { error ->
|
||||||
if (error is UserWalletsListError.WalletAlreadySaved) {
|
if (error is UserWalletsListError.WalletAlreadySaved) {
|
||||||
|
|
@ -556,7 +558,7 @@ class DetailsMiddleware {
|
||||||
store.onUserWalletSelected(userWallet)
|
store.onUserWalletSelected(userWallet)
|
||||||
|
|
||||||
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success)
|
||||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
} else {
|
} else {
|
||||||
Timber.e(error, "Unable to create user wallet")
|
Timber.e(error, "Unable to create user wallet")
|
||||||
handleError(error, prevUseBiometricsForAccessCode)
|
handleError(error, prevUseBiometricsForAccessCode)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.tap.features.details.redux
|
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.apptheme.model.AppThemeMode
|
||||||
import com.tangem.domain.common.CardTypesResolver
|
import com.tangem.domain.common.CardTypesResolver
|
||||||
import com.tangem.domain.common.util.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 {
|
private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: AppState): DetailsState {
|
||||||
|
val router = store.inject(DaggerGraphState::appRouter)
|
||||||
|
|
||||||
return DetailsState(
|
return DetailsState(
|
||||||
scanResponse = action.scanResponse,
|
scanResponse = action.scanResponse,
|
||||||
// If the current screen is ResetToFactory, we must save the ResetToFactory's state
|
// 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
|
state.detailsState.cardSettingsState
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|
@ -281,6 +283,9 @@ private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: Detail
|
||||||
isHidingEnabled = action.hideBalance,
|
isHidingEnabled = action.hideBalance,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
is DetailsAction.AppSettings.Prepare -> state.copy(
|
||||||
|
appSettingsState = action.state,
|
||||||
|
)
|
||||||
is DetailsAction.AppSettings.EnrollBiometrics,
|
is DetailsAction.AppSettings.EnrollBiometrics,
|
||||||
is DetailsAction.AppSettings.CheckBiometricsStatus,
|
is DetailsAction.AppSettings.CheckBiometricsStatus,
|
||||||
-> state
|
-> state
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
package com.tangem.tap.features.details.redux.walletconnect
|
package com.tangem.tap.features.details.redux.walletconnect
|
||||||
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import com.tangem.blockchain.common.WalletManager
|
import com.tangem.blockchain.common.WalletManager
|
||||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.domain.qrscanning.models.SourceType
|
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.dispatchOnMain
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.common.redux.AppDialog
|
import com.tangem.tap.common.redux.AppDialog
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
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.LegacyWalletConnectRepository
|
||||||
|
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
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.Account
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError
|
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError
|
||||||
|
|
@ -62,14 +60,7 @@ class WalletConnectMiddleware {
|
||||||
// TODO check
|
// TODO check
|
||||||
store.dispatchOnMain(WalletConnectAction.ShowClipboardOrScanQrDialog(uri))
|
store.dispatchOnMain(WalletConnectAction.ShowClipboardOrScanQrDialog(uri))
|
||||||
} else {
|
} else {
|
||||||
store.dispatchOnMain(
|
store.dispatchNavigationAction { push(AppRoute.QrScanning(SourceType.WALLET_CONNECT)) }
|
||||||
NavigationAction.NavigateTo(
|
|
||||||
screen = AppScreen.QrScanning,
|
|
||||||
bundle = bundleOf(
|
|
||||||
QrScanningRouter.SOURCE_KEY to SourceType.WALLET_CONNECT,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is WalletConnectAction.ShowClipboardOrScanQrDialog -> {
|
is WalletConnectAction.ShowClipboardOrScanQrDialog -> {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.blockchain.common.TransactionData
|
import com.tangem.blockchain.common.TransactionData
|
||||||
import com.tangem.blockchain.common.WalletManager
|
import com.tangem.blockchain.common.WalletManager
|
||||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
import com.tangem.tap.domain.walletconnect2.domain.WcPreparedRequest
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.WcSignMessage
|
import com.tangem.tap.domain.walletconnect2.domain.WcSignMessage
|
||||||
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents
|
import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.core.ui.UiDependencies
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.ui.components.SystemBarsEffect
|
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -22,12 +21,8 @@ internal class AppCurrencySelectorFragment : ComposeFragment() {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun ScreenContent(modifier: Modifier) {
|
override fun ScreenContent(modifier: Modifier) {
|
||||||
val systemBarsColor = TangemTheme.colors.background.secondary
|
|
||||||
SystemBarsEffect {
|
|
||||||
setSystemBarsColor(systemBarsColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
|
NavigationBar3ButtonsScrim()
|
||||||
AppCurrencySelectorScreen(
|
AppCurrencySelectorScreen(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
state = uiState,
|
state = uiState,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -40,7 +41,9 @@ internal fun AppCurrencySelectorScreen(state: AppCurrencySelectorState, modifier
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = modifier
|
||||||
|
.imePadding()
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
containerColor = TangemTheme.colors.background.secondary,
|
containerColor = TangemTheme.colors.background.secondary,
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBar(
|
TopBar(
|
||||||
|
|
@ -49,6 +52,7 @@ internal fun AppCurrencySelectorScreen(state: AppCurrencySelectorState, modifier
|
||||||
state = state,
|
state = state,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(WindowInsets.navigationBars),
|
||||||
content = { paddingValues ->
|
content = { paddingValues ->
|
||||||
val contentModifier = Modifier
|
val contentModifier = Modifier
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
|
|
@ -62,7 +66,7 @@ internal fun AppCurrencySelectorScreen(state: AppCurrencySelectorState, modifier
|
||||||
modifier = contentModifier,
|
modifier = contentModifier,
|
||||||
listState = listState,
|
listState = listState,
|
||||||
currencies = state.items,
|
currencies = state.items,
|
||||||
selectedId = state.selectedId.orEmpty(),
|
selectedId = state.selectedId,
|
||||||
onCurrencyClick = state.onCurrencyClick,
|
onCurrencyClick = state.onCurrencyClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -175,6 +179,7 @@ private fun SearchBar(onInputChange: (String) -> Unit, modifier: Modifier = Modi
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LoadingList(modifier: Modifier = Modifier) {
|
private fun LoadingList(modifier: Modifier = Modifier) {
|
||||||
|
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
repeat(times = 10) {
|
repeat(times = 10) {
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -199,6 +204,7 @@ private fun LoadingList(modifier: Modifier = Modifier) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Spacer(Modifier.height(bottomBarHeight))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,9 +216,11 @@ private fun CurrenciesList(
|
||||||
onCurrencyClick: (Currency) -> Unit,
|
onCurrencyClick: (Currency) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
state = listState,
|
state = listState,
|
||||||
|
contentPadding = PaddingValues(bottom = bottomBarHeight),
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = currencies,
|
items = currencies,
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ package com.tangem.tap.features.details.ui.appcurrency
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.navigation.ReduxNavController
|
|
||||||
import com.tangem.domain.appcurrency.GetAvailableCurrenciesUseCase
|
import com.tangem.domain.appcurrency.GetAvailableCurrenciesUseCase
|
||||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
import com.tangem.domain.appcurrency.SelectAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.SelectAppCurrencyUseCase
|
||||||
|
|
@ -20,7 +21,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
||||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||||
private val getAvailableCurrenciesUseCase: GetAvailableCurrenciesUseCase,
|
private val getAvailableCurrenciesUseCase: GetAvailableCurrenciesUseCase,
|
||||||
private val selectAppCurrencyUseCase: SelectAppCurrencyUseCase,
|
private val selectAppCurrencyUseCase: SelectAppCurrencyUseCase,
|
||||||
private val reduxNavController: ReduxNavController,
|
private val router: AppRouter,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
) : ViewModel(), AppCurrencySelectorIntents {
|
) : ViewModel(), AppCurrencySelectorIntents {
|
||||||
|
|
@ -34,7 +35,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
||||||
val uiState: StateFlow<AppCurrencySelectorState> = stateController.stateFlow
|
val uiState: StateFlow<AppCurrencySelectorState> = stateController.stateFlow
|
||||||
|
|
||||||
override fun onBackClick() {
|
override fun onBackClick() {
|
||||||
reduxNavController.popBackStack()
|
router.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSearchClick() {
|
override fun onSearchClick() {
|
||||||
|
|
@ -52,7 +53,7 @@ internal class AppCurrencySelectorViewModel @Inject constructor(
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
event = Settings.AppSettings.MainCurrencyChanged(currencyType = currency.name),
|
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.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
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.features.details.redux.DetailsAction
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -36,7 +38,7 @@ internal class AppSettingsFragment : ComposeFragment() {
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = {
|
onBackClick = {
|
||||||
store.dispatch(DetailsAction.ResetCardSettingsData)
|
store.dispatch(DetailsAction.ResetCardSettingsData)
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
package com.tangem.tap.features.details.ui.appsettings
|
package com.tangem.tap.features.details.ui.appsettings
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.systemBars
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||||
|
|
@ -32,6 +36,7 @@ internal fun AppSettingsScreen(state: AppSettingsScreenState, onBackClick: () ->
|
||||||
},
|
},
|
||||||
titleRes = R.string.app_settings_title,
|
titleRes = R.string.app_settings_title,
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
|
addBottomInsets = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,7 +49,11 @@ private fun AppSettings(state: AppSettingsScreenState.Content) {
|
||||||
null -> Unit
|
null -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn {
|
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(bottom = bottomBarHeight),
|
||||||
|
) {
|
||||||
items(
|
items(
|
||||||
items = state.items,
|
items = state.items,
|
||||||
key = Item::id,
|
key = Item::id,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
package com.tangem.tap.features.details.ui.appsettings
|
package com.tangem.tap.features.details.ui.appsettings
|
||||||
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.*
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import com.tangem.common.routing.AppRoute
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||||
|
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
||||||
|
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||||
|
import com.tangem.domain.settings.CanUseBiometryUseCase
|
||||||
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
|
import com.tangem.features.details.DetailsFeatureToggles
|
||||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||||
import com.tangem.tap.common.analytics.events.Settings
|
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.dispatchOnMain
|
||||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||||
import com.tangem.tap.features.details.redux.AppSetting
|
import com.tangem.tap.features.details.redux.AppSetting
|
||||||
|
|
@ -26,14 +30,22 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.rekotlin.StoreSubscriber
|
import org.rekotlin.StoreSubscriber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
internal class AppSettingsViewModel @Inject constructor(
|
internal class AppSettingsViewModel @Inject constructor(
|
||||||
private val appCurrencyRepository: AppCurrencyRepository,
|
private val appCurrencyRepository: AppCurrencyRepository,
|
||||||
|
private val walletsRepository: WalletsRepository,
|
||||||
|
private val canUseBiometryUseCase: CanUseBiometryUseCase,
|
||||||
|
private val balanceHidingRepository: BalanceHidingRepository,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
|
private val appThemeModeRepository: AppThemeModeRepository,
|
||||||
|
private val settingsRepository: SettingsRepository,
|
||||||
private val appSettingsItemsAnalyticsSender: AppSettingsItemsAnalyticsSender,
|
private val appSettingsItemsAnalyticsSender: AppSettingsItemsAnalyticsSender,
|
||||||
|
private val detailsFeatureToggles: DetailsFeatureToggles,
|
||||||
) : ViewModel(),
|
) : ViewModel(),
|
||||||
StoreSubscriber<DetailsState>,
|
StoreSubscriber<DetailsState>,
|
||||||
DefaultLifecycleObserver {
|
DefaultLifecycleObserver {
|
||||||
|
|
@ -50,6 +62,9 @@ internal class AppSettingsViewModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
bootstrapAppCurrencyUpdates()
|
bootstrapAppCurrencyUpdates()
|
||||||
|
if (detailsFeatureToggles.isRedesignEnabled) {
|
||||||
|
bootstrapBiometricsUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
subscribeToStoreChanges()
|
subscribeToStoreChanges()
|
||||||
sendItemsAnalytics()
|
sendItemsAnalytics()
|
||||||
|
|
@ -128,7 +143,7 @@ internal class AppSettingsViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAppCurrencySelector() {
|
private fun showAppCurrencySelector() {
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.AppCurrencySelector))
|
store.dispatchNavigationAction { push(AppRoute.AppCurrencySelector) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showThemeModeSelector(selectedMode: AppThemeMode) {
|
private fun showThemeModeSelector(selectedMode: AppThemeMode) {
|
||||||
|
|
@ -214,6 +229,19 @@ internal class AppSettingsViewModel @Inject constructor(
|
||||||
.saveIn(appCurrencyUpdatesJobHolder)
|
.saveIn(appCurrencyUpdatesJobHolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bootstrapBiometricsUpdates() = viewModelScope.launch {
|
||||||
|
val state = AppSettingsState(
|
||||||
|
saveWallets = walletsRepository.shouldSaveUserWalletsSync(),
|
||||||
|
saveAccessCodes = settingsRepository.shouldSaveAccessCodes(),
|
||||||
|
isBiometricsAvailable = canUseBiometryUseCase(),
|
||||||
|
isHidingEnabled = balanceHidingRepository.getBalanceHidingSettings().isHidingEnabledInSettings,
|
||||||
|
selectedAppCurrency = appCurrencyRepository.getSelectedAppCurrency().firstOrNull() ?: AppCurrency.Default,
|
||||||
|
selectedThemeMode = appThemeModeRepository.getAppThemeMode().firstOrNull() ?: AppThemeMode.DEFAULT,
|
||||||
|
)
|
||||||
|
|
||||||
|
store.dispatchWithMain(DetailsAction.AppSettings.Prepare(state))
|
||||||
|
}
|
||||||
|
|
||||||
private fun subscribeToStoreChanges() {
|
private fun subscribeToStoreChanges() {
|
||||||
store.subscribe(subscriber = this) { state ->
|
store.subscribe(subscriber = this) { state ->
|
||||||
state.skipRepeats { oldState, newState ->
|
state.skipRepeats { oldState, newState ->
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.fragment.app.viewModels
|
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.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
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.features.details.redux.DetailsAction
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -29,7 +31,7 @@ internal class CardSettingsFragment : ComposeFragment() {
|
||||||
state = viewModel.screenState.value,
|
state = viewModel.screenState.value,
|
||||||
onBackClick = {
|
onBackClick = {
|
||||||
store.dispatch(DetailsAction.ResetCardSettingsData)
|
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.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.ui.Modifier
|
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.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
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.features.details.redux.DetailsState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -28,7 +29,7 @@ class AccessCodeRecoveryFragment : ComposeFragment(), StoreSubscriber<DetailsSta
|
||||||
override fun ScreenContent(modifier: Modifier) {
|
override fun ScreenContent(modifier: Modifier) {
|
||||||
AccessCodeRecoveryScreen(
|
AccessCodeRecoveryScreen(
|
||||||
state = screenState.value,
|
state = screenState.value,
|
||||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||||
import com.tangem.core.ui.components.SystemBarsEffect
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.utils.WindowInsetsZero
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -24,31 +24,42 @@ internal fun SettingsScreensScaffold(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@StringRes titleRes: Int? = null,
|
@StringRes titleRes: Int? = null,
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
|
addBottomInsets: Boolean = true,
|
||||||
fab: @Composable () -> Unit = {},
|
fab: @Composable () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val state = rememberScaffoldState(snackbarHostState = snackbarHostState)
|
val state = rememberScaffoldState(snackbarHostState = snackbarHostState)
|
||||||
val backgroundColor = TangemTheme.colors.background.secondary
|
val backgroundColor = TangemTheme.colors.background.secondary
|
||||||
|
|
||||||
BackHandler(onBack = onBackClick)
|
BackHandler(onBack = onBackClick)
|
||||||
SystemBarsEffect {
|
|
||||||
setSystemBarsColor(backgroundColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
scaffoldState = state,
|
scaffoldState = state,
|
||||||
topBar = {
|
topBar = {
|
||||||
EmptyTopBarWithNavigation(
|
EmptyTopBarWithNavigation(
|
||||||
|
modifier = Modifier.statusBarsPadding(),
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
backgroundColor = backgroundColor,
|
backgroundColor = backgroundColor,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
modifier = modifier.systemBarsPadding(),
|
modifier = modifier,
|
||||||
|
contentWindowInsets = WindowInsetsZero,
|
||||||
backgroundColor = backgroundColor,
|
backgroundColor = backgroundColor,
|
||||||
floatingActionButton = fab,
|
floatingActionButton = {
|
||||||
content = { paddings ->
|
Box(modifier = Modifier.navigationBarsPadding()) {
|
||||||
|
fab()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
content = { paddingValues ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(paddings)
|
.run {
|
||||||
|
if (addBottomInsets) {
|
||||||
|
navigationBarsPadding()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(paddingValues)
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
if (titleRes != null) {
|
if (titleRes != null) {
|
||||||
|
|
@ -81,9 +92,11 @@ internal fun ScreenTitle(titleRes: Int, modifier: Modifier = Modifier) {
|
||||||
@Composable
|
@Composable
|
||||||
internal fun EmptyTopBarWithNavigation(
|
internal fun EmptyTopBarWithNavigation(
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
backgroundColor: Color = TangemTheme.colors.background.primary,
|
backgroundColor: Color = TangemTheme.colors.background.primary,
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
modifier = modifier,
|
||||||
title = { },
|
title = { },
|
||||||
navigationIcon =
|
navigationIcon =
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@ package com.tangem.tap.features.details.ui.details
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.core.ui.UiDependencies
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.tap.common.analytics.events.Settings
|
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.features.details.redux.DetailsState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -45,7 +46,7 @@ internal class DetailsFragment : ComposeFragment(), StoreSubscriber<DetailsState
|
||||||
DetailsScreen(
|
DetailsScreen(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
state = detailsViewModel.detailsScreenState.value,
|
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.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import com.tangem.common.extensions.guard
|
import com.tangem.common.extensions.guard
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.core.ui.event.StateEvent
|
import com.tangem.core.ui.event.StateEvent
|
||||||
import com.tangem.core.ui.event.consumedEvent
|
import com.tangem.core.ui.event.consumedEvent
|
||||||
import com.tangem.core.ui.event.triggeredEvent
|
import com.tangem.core.ui.event.triggeredEvent
|
||||||
|
|
@ -16,15 +16,14 @@ import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.tap.common.analytics.events.Settings
|
import com.tangem.tap.common.analytics.events.Settings
|
||||||
import com.tangem.tap.common.extensions.addContext
|
import com.tangem.tap.common.extensions.*
|
||||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
|
||||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
|
||||||
import com.tangem.tap.common.feedback.FeedbackEmail
|
import com.tangem.tap.common.feedback.FeedbackEmail
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
import com.tangem.tap.features.details.redux.DetailsAction
|
import com.tangem.tap.features.details.redux.DetailsAction
|
||||||
import com.tangem.tap.features.details.redux.DetailsState
|
import com.tangem.tap.features.details.redux.DetailsState
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
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.LocaleRegionProvider
|
||||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||||
import com.tangem.tap.scope
|
import com.tangem.tap.scope
|
||||||
|
|
@ -128,15 +127,17 @@ internal class DetailsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToTesterMenu() {
|
private fun navigateToTesterMenu() {
|
||||||
store.state.daggerGraphState.testerRouter?.startTesterScreen()
|
store.dispatchNavigationAction {
|
||||||
|
push(AppRoute.TesterMenu)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToToS() {
|
private fun navigateToToS() {
|
||||||
store.dispatchOnMain(DisclaimerAction.Show(AppScreen.Details))
|
store.dispatchOnMain(DisclaimerAction.Show(DisclaimerSource.Details))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToReferralProgram() {
|
private fun navigateToReferralProgram() {
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.ReferralProgram))
|
store.dispatchNavigationAction { push(AppRoute.ReferralProgram) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendFeedback() {
|
private fun sendFeedback() {
|
||||||
|
|
@ -146,12 +147,12 @@ internal class DetailsViewModel(
|
||||||
|
|
||||||
private fun navigateToAppSettings() {
|
private fun navigateToAppSettings() {
|
||||||
Analytics.send(Settings.ButtonAppSettings())
|
Analytics.send(Settings.ButtonAppSettings())
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.AppSettings))
|
store.dispatchNavigationAction { push(AppRoute.AppSettings) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToCardSettings() {
|
private fun navigateToCardSettings() {
|
||||||
Analytics.send(Settings.ButtonCardSettings())
|
Analytics.send(Settings.ButtonCardSettings())
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.CardSettings))
|
store.dispatchNavigationAction { push(AppRoute.CardSettings) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun linkMoreCards() {
|
private fun linkMoreCards() {
|
||||||
|
|
@ -164,7 +165,7 @@ internal class DetailsViewModel(
|
||||||
val scanResponse = selectedUserWallet.scanResponse
|
val scanResponse = selectedUserWallet.scanResponse
|
||||||
Analytics.addContext(scanResponse)
|
Analytics.addContext(scanResponse)
|
||||||
store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false))
|
store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false))
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
store.dispatchNavigationAction { push(AppRoute.OnboardingWallet()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scanAndSaveUserWallet() {
|
private fun scanAndSaveUserWallet() {
|
||||||
|
|
@ -174,12 +175,12 @@ internal class DetailsViewModel(
|
||||||
|
|
||||||
private fun navigateToWalletConnect() {
|
private fun navigateToWalletConnect() {
|
||||||
Analytics.send(Settings.ButtonWalletConnect())
|
Analytics.send(Settings.ButtonWalletConnect())
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
|
store.dispatchNavigationAction { push(AppRoute.WalletConnectSessions) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSocialNetworkClick(link: SocialNetworkLink) {
|
private fun handleSocialNetworkClick(link: SocialNetworkLink) {
|
||||||
Analytics.send(Settings.ButtonSocialNetwork(link.network))
|
Analytics.send(Settings.ButtonSocialNetwork(link.network))
|
||||||
store.dispatchOnMain(NavigationAction.OpenUrl(link.url))
|
store.dispatchOpenUrl(link.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSocialLinks(): ImmutableList<SocialNetworkLink> {
|
private fun getSocialLinks(): ImmutableList<SocialNetworkLink> {
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
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.features.details.redux.DetailsState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -30,7 +31,7 @@ internal class ResetCardFragment : ComposeFragment(), StoreSubscriber<DetailsSta
|
||||||
|
|
||||||
ResetCardScreen(
|
ResetCardScreen(
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
onBackClick = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,15 @@ package com.tangem.tap.features.details.ui.resetcard
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
import com.tangem.common.routing.utils.popTo
|
||||||
|
|
||||||
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||||
import com.tangem.domain.card.ResetCardUseCase
|
import com.tangem.domain.card.ResetCardUseCase
|
||||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
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.common.extensions.onUserWalletSelected
|
||||||
import com.tangem.tap.features.details.redux.CardSettingsState
|
import com.tangem.tap.features.details.redux.CardSettingsState
|
||||||
import com.tangem.tap.features.details.redux.DetailsAction.ResetToFactory
|
import com.tangem.tap.features.details.redux.DetailsAction.ResetToFactory
|
||||||
|
|
@ -165,9 +167,9 @@ internal class ResetCardViewModel @Inject constructor(
|
||||||
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrNull()
|
val newSelectedWallet = getSelectedWalletSyncUseCase().getOrNull()
|
||||||
|
|
||||||
if (newSelectedWallet != null) {
|
if (newSelectedWallet != null) {
|
||||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
} else {
|
} 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.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.ui.Modifier
|
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.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
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.features.details.redux.DetailsState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -29,7 +30,7 @@ internal class SecurityModeFragment : ComposeFragment(), StoreSubscriber<Details
|
||||||
SecurityModeScreen(
|
SecurityModeScreen(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
state = screenState.value,
|
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.runtime.mutableStateOf
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.core.ui.UiDependencies
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
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.features.details.redux.walletconnect.WalletConnectState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -41,7 +42,7 @@ internal class WalletConnectFragment : ComposeFragment(), StoreSubscriber<Wallet
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = {
|
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 android.content.Context
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
|
||||||
import com.tangem.domain.qrscanning.models.SourceType
|
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.common.redux.global.GlobalAction
|
||||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -22,14 +20,9 @@ object ClipboardOrScanQrDialog {
|
||||||
store.dispatch(WalletConnectAction.OpenSession(wcUri))
|
store.dispatch(WalletConnectAction.OpenSession(wcUri))
|
||||||
}
|
}
|
||||||
setNegativeButton(context.getText(R.string.wallet_connect_scan_new_code)) { _, _ ->
|
setNegativeButton(context.getText(R.string.wallet_connect_scan_new_code)) { _, _ ->
|
||||||
store.dispatch(
|
store.dispatchNavigationAction {
|
||||||
NavigationAction.NavigateTo(
|
push(AppRoute.QrScanning(source = SourceType.WALLET_CONNECT))
|
||||||
screen = AppScreen.QrScanning,
|
}
|
||||||
bundle = bundleOf(
|
|
||||||
QrScanningRouter.SOURCE_KEY to SourceType.WALLET_CONNECT,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
setOnDismissListener {
|
setOnDismissListener {
|
||||||
store.dispatch(GlobalAction.HideDialog)
|
store.dispatch(GlobalAction.HideDialog)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.tangem.tap.features.disclaimer.redux
|
package com.tangem.tap.features.disclaimer.redux
|
||||||
|
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.tap.common.entities.ProgressState
|
import com.tangem.tap.common.entities.ProgressState
|
||||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||||
import org.rekotlin.Action
|
import org.rekotlin.Action
|
||||||
|
|
@ -10,7 +9,7 @@ sealed class DisclaimerAction : Action {
|
||||||
data class SetDisclaimer(val disclaimer: Disclaimer) : DisclaimerAction()
|
data class SetDisclaimer(val disclaimer: Disclaimer) : DisclaimerAction()
|
||||||
|
|
||||||
data class Show(
|
data class Show(
|
||||||
val fromScreen: AppScreen,
|
val from: DisclaimerSource,
|
||||||
val callback: DisclaimerCallback? = null,
|
val callback: DisclaimerCallback? = null,
|
||||||
) : DisclaimerAction()
|
) : DisclaimerAction()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package com.tangem.tap.features.disclaimer.redux
|
package com.tangem.tap.features.disclaimer.redux
|
||||||
|
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
import com.tangem.common.routing.AppRouter
|
||||||
|
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.mainScope
|
import com.tangem.tap.mainScope
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -25,17 +26,19 @@ private fun handleDisclaimerMiddleware(action: Action, appState: AppState) {
|
||||||
|
|
||||||
when (action) {
|
when (action) {
|
||||||
is DisclaimerAction.Show -> {
|
is DisclaimerAction.Show -> {
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
|
store.dispatchNavigationAction {
|
||||||
|
push(AppRoute.Disclaimer(isTosAccepted = action.from == DisclaimerSource.Details))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is DisclaimerAction.AcceptDisclaimer -> {
|
is DisclaimerAction.AcceptDisclaimer -> {
|
||||||
mainScope.launch {
|
mainScope.launch {
|
||||||
state.disclaimer.accept()
|
state.disclaimer.accept()
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
state.callback?.onAccept?.invoke()
|
state.callback?.onAccept?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is DisclaimerAction.OnBackPressed -> {
|
is DisclaimerAction.OnBackPressed -> {
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
state.callback?.onDismiss?.invoke()
|
state.callback?.onDismiss?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ private fun internalReduce(action: Action, state: AppState): DisclaimerState {
|
||||||
disclaimer = action.disclaimer,
|
disclaimer = action.disclaimer,
|
||||||
)
|
)
|
||||||
is DisclaimerAction.Show -> disclaimerState.copy(
|
is DisclaimerAction.Show -> disclaimerState.copy(
|
||||||
showedFromScreen = action.fromScreen,
|
showedFrom = action.from,
|
||||||
callback = action.callback,
|
callback = action.callback,
|
||||||
)
|
)
|
||||||
is DisclaimerAction.AcceptDisclaimer, is DisclaimerAction.OnBackPressed -> disclaimerState.copy(
|
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
|
package com.tangem.tap.features.disclaimer.redux
|
||||||
|
|
||||||
import com.tangem.common.extensions.VoidCallback
|
import com.tangem.common.extensions.VoidCallback
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.tap.common.entities.ProgressState
|
import com.tangem.tap.common.entities.ProgressState
|
||||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||||
import com.tangem.tap.features.disclaimer.DummyDisclaimer
|
import com.tangem.tap.features.disclaimer.DummyDisclaimer
|
||||||
|
|
@ -9,7 +9,7 @@ import org.rekotlin.StateType
|
||||||
|
|
||||||
data class DisclaimerState(
|
data class DisclaimerState(
|
||||||
val disclaimer: Disclaimer = DummyDisclaimer(),
|
val disclaimer: Disclaimer = DummyDisclaimer(),
|
||||||
val showedFromScreen: AppScreen = AppScreen.Home,
|
val showedFrom: DisclaimerSource = DisclaimerSource.Home,
|
||||||
val callback: DisclaimerCallback? = null,
|
val callback: DisclaimerCallback? = null,
|
||||||
val progressState: ProgressState? = null,
|
val progressState: ProgressState? = null,
|
||||||
) : StateType
|
) : StateType
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import android.webkit.WebView
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.transition.TransitionInflater
|
import androidx.transition.TransitionInflater
|
||||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.ui.extensions.setStatusBarColor
|
import com.tangem.core.ui.extensions.setStatusBarColor
|
||||||
import com.tangem.tap.common.entities.ProgressState
|
import com.tangem.tap.common.entities.ProgressState
|
||||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
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.addBackPressHandler
|
||||||
import com.tangem.tap.features.disclaimer.Disclaimer
|
import com.tangem.tap.features.disclaimer.Disclaimer
|
||||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
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.features.disclaimer.redux.DisclaimerState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
@ -76,17 +77,14 @@ class DisclaimerFragment : BaseFragment(R.layout.fragment_disclaimer), StoreSubs
|
||||||
|
|
||||||
override fun configureTransitions() {
|
override fun configureTransitions() {
|
||||||
val inflater = TransitionInflater.from(requireContext())
|
val inflater = TransitionInflater.from(requireContext())
|
||||||
when (store.state.disclaimerState.showedFromScreen) {
|
when (store.state.disclaimerState.showedFrom) {
|
||||||
AppScreen.Home -> {
|
DisclaimerSource.Home -> {
|
||||||
enterTransition = inflater.inflateTransition(android.R.transition.slide_bottom)
|
enterTransition = inflater.inflateTransition(android.R.transition.slide_bottom)
|
||||||
exitTransition = inflater.inflateTransition(android.R.transition.slide_top)
|
exitTransition = inflater.inflateTransition(android.R.transition.slide_top)
|
||||||
}
|
}
|
||||||
AppScreen.Details -> {
|
DisclaimerSource.Details -> {
|
||||||
super.configureTransitions()
|
super.configureTransitions()
|
||||||
}
|
}
|
||||||
else -> {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,16 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.core.view.WindowCompat
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
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.UiDependencies
|
||||||
import com.tangem.core.ui.components.SystemBarsEffect
|
import com.tangem.core.ui.components.SystemBarsIconsDisposable
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import com.tangem.domain.tokens.TokensAction
|
import com.tangem.domain.tokens.TokensAction
|
||||||
import com.tangem.tap.common.analytics.events.IntroductionProcess
|
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.common.redux.AppState
|
||||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||||
import com.tangem.tap.features.home.redux.HomeAction
|
import com.tangem.tap.features.home.redux.HomeAction
|
||||||
|
|
@ -43,15 +42,12 @@ class HomeFragment : ComposeFragment(), StoreSubscriber<HomeState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun ScreenContent(modifier: Modifier) {
|
override fun ScreenContent(modifier: Modifier) {
|
||||||
BackHandler(onBack = requireActivity()::finish)
|
BackHandler(onBack = requireActivity()::finish)
|
||||||
SystemBarsEffect {
|
SystemBarsIconsDisposable(darkIcons = false)
|
||||||
setSystemBarsColor(color = Color.Transparent, darkIcons = false)
|
|
||||||
}
|
|
||||||
ScreenContent()
|
ScreenContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, false) }
|
|
||||||
|
|
||||||
store.subscribe(subscriber = this) { state ->
|
store.subscribe(subscriber = this) { state ->
|
||||||
state
|
state
|
||||||
|
|
@ -86,7 +82,7 @@ class HomeFragment : ComposeFragment(), StoreSubscriber<HomeState> {
|
||||||
},
|
},
|
||||||
onSearchTokensClick = {
|
onSearchTokensClick = {
|
||||||
Analytics.send(IntroductionProcess.ButtonTokensList())
|
Analytics.send(IntroductionProcess.ButtonTokensList())
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.ManageTokens))
|
store.dispatchNavigationAction { push(AppRoute.ManageTokens) }
|
||||||
store.dispatch(TokensAction.SetArgs.ReadAccess)
|
store.dispatch(TokensAction.SetArgs.ReadAccess)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@ import com.tangem.common.doOnFailure
|
||||||
import com.tangem.common.doOnResult
|
import com.tangem.common.doOnResult
|
||||||
import com.tangem.common.doOnSuccess
|
import com.tangem.common.doOnSuccess
|
||||||
import com.tangem.common.extensions.guard
|
import com.tangem.common.extensions.guard
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||||
|
|
@ -119,7 +118,7 @@ private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch {
|
||||||
scope.launch { store.onUserWalletSelected(userWallet = userWallet) }
|
scope.launch { store.onUserWalletSelected(userWallet = userWallet) }
|
||||||
}
|
}
|
||||||
.doOnResult {
|
.doOnResult {
|
||||||
navigateTo(AppScreen.Wallet)
|
navigateTo(AppRoute.Wallet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,8 +142,8 @@ private fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun navigateTo(appScreen: AppScreen) {
|
private suspend fun navigateTo(route: AppRoute) {
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(appScreen))
|
store.dispatchNavigationAction { push(route) }
|
||||||
delay(HIDE_PROGRESS_DELAY)
|
delay(HIDE_PROGRESS_DELAY)
|
||||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress = false))
|
store.dispatch(HomeAction.ScanInProgress(scanInProgress = false))
|
||||||
}
|
}
|
||||||
|
|
@ -3,11 +3,11 @@ package com.tangem.tap.features.main
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
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.Analytics
|
||||||
import com.tangem.core.analytics.models.Basic
|
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.appcurrency.FetchAppCurrenciesUseCase
|
||||||
import com.tangem.domain.balancehiding.BalanceHidingSettings
|
import com.tangem.domain.balancehiding.BalanceHidingSettings
|
||||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||||
|
|
@ -16,9 +16,11 @@ import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
||||||
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
||||||
import com.tangem.domain.settings.DeleteDeprecatedLogsUseCase
|
import com.tangem.domain.settings.DeleteDeprecatedLogsUseCase
|
||||||
import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
|
import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
|
||||||
|
import com.tangem.domain.staking.FetchStakingTokensUseCase
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
|
||||||
|
import com.tangem.features.staking.api.featuretoggles.StakingFeatureToggles
|
||||||
import com.tangem.tap.common.extensions.setContext
|
import com.tangem.tap.common.extensions.setContext
|
||||||
import com.tangem.tap.features.main.model.MainScreenState
|
import com.tangem.tap.features.main.model.MainScreenState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -34,7 +36,7 @@ import javax.inject.Inject
|
||||||
internal class MainViewModel @Inject constructor(
|
internal class MainViewModel @Inject constructor(
|
||||||
private val updateBalanceHidingSettingsUseCase: UpdateBalanceHidingSettingsUseCase,
|
private val updateBalanceHidingSettingsUseCase: UpdateBalanceHidingSettingsUseCase,
|
||||||
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
||||||
private val reduxNavController: ReduxNavController,
|
private val router: AppRouter,
|
||||||
private val fetchAppCurrenciesUseCase: FetchAppCurrenciesUseCase,
|
private val fetchAppCurrenciesUseCase: FetchAppCurrenciesUseCase,
|
||||||
private val deleteDeprecatedLogsUseCase: DeleteDeprecatedLogsUseCase,
|
private val deleteDeprecatedLogsUseCase: DeleteDeprecatedLogsUseCase,
|
||||||
private val incrementAppLaunchCounterUseCase: IncrementAppLaunchCounterUseCase,
|
private val incrementAppLaunchCounterUseCase: IncrementAppLaunchCounterUseCase,
|
||||||
|
|
@ -44,6 +46,8 @@ internal class MainViewModel @Inject constructor(
|
||||||
private val sendFeatureToggles: SendFeatureToggles,
|
private val sendFeatureToggles: SendFeatureToggles,
|
||||||
private val feedbackManagerFeatureToggles: FeedbackManagerFeatureToggles,
|
private val feedbackManagerFeatureToggles: FeedbackManagerFeatureToggles,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
|
private val stakingFeatureToggles: StakingFeatureToggles,
|
||||||
|
private val fetchStakingTokensUseCase: FetchStakingTokensUseCase,
|
||||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||||
) : ViewModel(), MainIntents {
|
) : ViewModel(), MainIntents {
|
||||||
|
|
||||||
|
|
@ -70,6 +74,10 @@ internal class MainViewModel @Inject constructor(
|
||||||
displayBalancesHidingStatusToast()
|
displayBalancesHidingStatusToast()
|
||||||
displayHiddenBalancesModalNotification()
|
displayHiddenBalancesModalNotification()
|
||||||
|
|
||||||
|
if (stakingFeatureToggles.isStakingEnabled) {
|
||||||
|
fetchStakingTokens()
|
||||||
|
}
|
||||||
|
|
||||||
viewModelScope.launch(dispatchers.main) {
|
viewModelScope.launch(dispatchers.main) {
|
||||||
deleteDeprecatedLogsUseCase()
|
deleteDeprecatedLogsUseCase()
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +123,14 @@ internal class MainViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fetchStakingTokens() {
|
||||||
|
viewModelScope.launch(dispatchers.main) {
|
||||||
|
fetchStakingTokensUseCase()
|
||||||
|
.onLeft { Timber.e(it, "Unable to fetch the staking tokens list") }
|
||||||
|
.onRight { Timber.d("Staking token list was fetched successfully") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateSendFeatureToggle() {
|
private fun updateSendFeatureToggle() {
|
||||||
viewModelScope.launch(dispatchers.main) {
|
viewModelScope.launch(dispatchers.main) {
|
||||||
sendFeatureToggles.fetchNewSendEnabled()
|
sendFeatureToggles.fetchNewSendEnabled()
|
||||||
|
|
@ -136,7 +152,7 @@ internal class MainViewModel @Inject constructor(
|
||||||
if (state.value.modalNotification?.isShow != true && !it.isUpdateFromToast) {
|
if (state.value.modalNotification?.isShow != true && !it.isUpdateFromToast) {
|
||||||
listenToFlipsUseCase.changeUpdateEnabled(false)
|
listenToFlipsUseCase.changeUpdateEnabled(false)
|
||||||
stateHolder.updateWithHiddenBalancesNotification()
|
stateHolder.updateWithHiddenBalancesNotification()
|
||||||
reduxNavController.navigate(NavigationAction.NavigateTo(AppScreen.ModalNotification))
|
router.push(AppRoute.ModalNotification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.features.onboarding
|
package com.tangem.tap.features.onboarding
|
||||||
|
|
||||||
import com.tangem.common.extensions.VoidCallback
|
import com.tangem.common.extensions.VoidCallback
|
||||||
import com.tangem.core.navigation.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ package com.tangem.tap.features.onboarding
|
||||||
import com.tangem.common.doOnFailure
|
import com.tangem.common.doOnFailure
|
||||||
import com.tangem.common.doOnSuccess
|
import com.tangem.common.doOnSuccess
|
||||||
import com.tangem.common.extensions.guard
|
import com.tangem.common.extensions.guard
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.Basic
|
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.cardTypesResolver
|
||||||
import com.tangem.domain.common.util.twinsIsTwinned
|
import com.tangem.domain.common.util.twinsIsTwinned
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
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) {
|
return when (val type = scanResponse.productType) {
|
||||||
ProductType.Note -> AppScreen.OnboardingNote
|
ProductType.Note -> AppRoute.OnboardingNote
|
||||||
ProductType.Wallet,
|
ProductType.Wallet,
|
||||||
ProductType.Wallet2,
|
ProductType.Wallet2,
|
||||||
ProductType.Ring,
|
ProductType.Ring,
|
||||||
-> if (scanResponse.card.settings.isBackupAllowed) {
|
-> if (scanResponse.card.settings.isBackupAllowed) {
|
||||||
AppScreen.OnboardingWallet
|
AppRoute.OnboardingWallet()
|
||||||
} else {
|
} else {
|
||||||
AppScreen.OnboardingOther
|
AppRoute.OnboardingOther
|
||||||
}
|
}
|
||||||
ProductType.Twins -> AppScreen.OnboardingTwins
|
ProductType.Twins -> AppRoute.OnboardingTwins
|
||||||
ProductType.Start2Coin,
|
ProductType.Start2Coin,
|
||||||
ProductType.Visa,
|
ProductType.Visa,
|
||||||
-> throw UnsupportedOperationException("Onboarding for ${type.name} cards is not supported")
|
-> throw UnsupportedOperationException("Onboarding for ${type.name} cards is not supported")
|
||||||
|
|
@ -111,14 +111,14 @@ object OnboardingHelper {
|
||||||
backupCardsIds = backupCardsIds?.toSet(),
|
backupCardsIds = backupCardsIds?.toSet(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { push(AppRoute.Wallet) }
|
||||||
delay(timeMillis = 1_800)
|
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
|
// If device has no biometry and save wallet screen has been shown, then go through old scenario
|
||||||
else -> {
|
else -> {
|
||||||
proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError)
|
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.CompletionResult
|
||||||
import com.tangem.common.extensions.guard
|
import com.tangem.common.extensions.guard
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
|
|
@ -204,7 +205,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
|
||||||
OnboardingDialog.InterruptOnboarding(
|
OnboardingDialog.InterruptOnboarding(
|
||||||
onOk = {
|
onOk = {
|
||||||
OnboardingHelper.onInterrupted()
|
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.blockchain.extensions.Result
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.extensions.guard
|
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.analytics.Analytics
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||||
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
import com.tangem.domain.common.extensions.makePrimaryWalletManager
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
|
|
@ -39,6 +40,7 @@ import kotlinx.coroutines.runBlocking
|
||||||
import org.rekotlin.Action
|
import org.rekotlin.Action
|
||||||
import org.rekotlin.DispatchFunction
|
import org.rekotlin.DispatchFunction
|
||||||
import org.rekotlin.Middleware
|
import org.rekotlin.Middleware
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
object TwinCardsMiddleware {
|
object TwinCardsMiddleware {
|
||||||
val handler = twinsWalletMiddleware
|
val handler = twinsWalletMiddleware
|
||||||
|
|
@ -328,7 +330,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
||||||
if (walletsRepository.shouldSaveUserWalletsSync()) {
|
if (walletsRepository.shouldSaveUserWalletsSync()) {
|
||||||
OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse)
|
OnboardingHelper.trySaveWalletAndNavigateToWalletScreen(scanResponse)
|
||||||
} else {
|
} 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)
|
store.dispatch(TwinCardsAction.CardsManager.Release)
|
||||||
|
|
||||||
action.shouldResetTwinCardsWidget(shouldReturnCardBack) {
|
action.shouldResetTwinCardsWidget(shouldReturnCardBack) {
|
||||||
store.dispatchOnMain(NavigationAction.PopBackTo(getPopBackScreen()))
|
store.dispatchNavigationAction { popTo(routeClass = getPopBackScreen()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store.dispatchDialogShow(OnboardingDialog.InterruptOnboarding(onOkCallback))
|
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)
|
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
|
||||||
|
|
||||||
return if (userWalletsListManager.hasUserWallets) {
|
return if (userWalletsListManager.hasUserWallets) {
|
||||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }
|
||||||
.fold(onSuccess = { true }, onFailure = { false })
|
.fold(onSuccess = { true }, onFailure = { false })
|
||||||
|
|
||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
AppScreen.Welcome
|
AppRoute.Welcome::class
|
||||||
} else {
|
} else {
|
||||||
AppScreen.Wallet
|
AppRoute.Wallet::class
|
||||||
}
|
}
|
||||||
} else {
|
} 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.guard
|
||||||
import com.tangem.common.extensions.ifNotNull
|
import com.tangem.common.extensions.ifNotNull
|
||||||
import com.tangem.common.extensions.toHexString
|
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.common.services.Result
|
||||||
import com.tangem.core.analytics.Analytics
|
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.extensions.withMainContext
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
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.builder.UserWalletBuilder
|
||||||
|
import com.tangem.domain.wallets.models.Artwork
|
||||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
||||||
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator
|
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.*
|
||||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||||
import com.tangem.tap.common.analytics.events.Onboarding
|
import com.tangem.tap.common.analytics.events.Onboarding
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
import com.tangem.tap.common.extensions.*
|
||||||
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.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
|
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
|
||||||
|
|
@ -164,7 +161,7 @@ private fun handleWalletAction(action: Action) {
|
||||||
store.dispatch(GlobalAction.Onboarding.Stop)
|
store.dispatch(GlobalAction.Onboarding.Stop)
|
||||||
|
|
||||||
if (scanResponse == null) {
|
if (scanResponse == null) {
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
store.dispatch(HomeAction.ReadCard(scope = action.scope))
|
store.dispatch(HomeAction.ReadCard(scope = action.scope))
|
||||||
} else {
|
} else {
|
||||||
val backupState = store.state.onboardingWalletState.backupState
|
val backupState = store.state.onboardingWalletState.backupState
|
||||||
|
|
@ -529,7 +526,8 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
||||||
addedBackupCardsCount = backupService.addedBackupCardsCount,
|
addedBackupCardsCount = backupService.addedBackupCardsCount,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
|
|
||||||
|
store.dispatchNavigationAction { push(AppRoute.OnboardingWallet()) }
|
||||||
}
|
}
|
||||||
is BackupAction.SkipBackup -> {
|
is BackupAction.SkipBackup -> {
|
||||||
Analytics.send(Onboarding.Backup.Skipped())
|
Analytics.send(Onboarding.Backup.Skipped())
|
||||||
|
|
@ -614,7 +612,7 @@ private fun handleOnBackPressed(state: OnboardingWalletState) {
|
||||||
}
|
}
|
||||||
BackupStep.Finished -> {
|
BackupStep.Finished -> {
|
||||||
OnboardingHelper.onInterrupted()
|
OnboardingHelper.onInterrupted()
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -625,7 +623,7 @@ private fun showInterruptOnboardingDialog() {
|
||||||
onOk = {
|
onOk = {
|
||||||
OnboardingHelper.onInterrupted()
|
OnboardingHelper.onInterrupted()
|
||||||
store.dispatch(BackupAction.DiscardBackup)
|
store.dispatch(BackupAction.DiscardBackup)
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.tangem.core.navigation.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import org.rekotlin.StateType
|
import org.rekotlin.StateType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.windowsize.rememberWindowSize
|
||||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseScreen
|
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseScreen
|
||||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseApi
|
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseApi
|
||||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen
|
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen
|
||||||
|
|
@ -16,6 +20,7 @@ import com.tangem.wallet.R
|
||||||
*/
|
*/
|
||||||
internal class OnboardingSeedPhraseStateHandler(
|
internal class OnboardingSeedPhraseStateHandler(
|
||||||
private val onboardingSeedPhraseApi: OnboardingSeedPhraseApi = OnboardingSeedPhraseScreen(),
|
private val onboardingSeedPhraseApi: OnboardingSeedPhraseApi = OnboardingSeedPhraseScreen(),
|
||||||
|
private val activity: Activity,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun newState(
|
fun newState(
|
||||||
|
|
@ -49,11 +54,16 @@ internal class OnboardingSeedPhraseStateHandler(
|
||||||
val subScreen = viewModel.currentScreen.collectAsState().value
|
val subScreen = viewModel.currentScreen.collectAsState().value
|
||||||
setMainScreenToolbarTitle(walletFragment, subScreen)
|
setMainScreenToolbarTitle(walletFragment, subScreen)
|
||||||
|
|
||||||
onboardingSeedPhraseApi.ScreenContent(
|
TangemTheme(
|
||||||
uiState = viewModel.uiState,
|
isDark = isSystemInDarkTheme(),
|
||||||
subScreen = subScreen,
|
windowSize = rememberWindowSize(activity = activity),
|
||||||
progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress,
|
) {
|
||||||
)
|
onboardingSeedPhraseApi.ScreenContent(
|
||||||
|
uiState = viewModel.uiState,
|
||||||
|
subScreen = subScreen,
|
||||||
|
progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,13 @@ import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import com.tangem.common.CardIdFormatter
|
import com.tangem.common.CardIdFormatter
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.core.CardIdDisplayFormat
|
import com.tangem.common.core.CardIdDisplayFormat
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.ui.extensions.setStatusBarColor
|
import com.tangem.core.ui.extensions.setStatusBarColor
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
|
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.analytics.SeedPhraseSource
|
||||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseMediator
|
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseMediator
|
||||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseRouter
|
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseRouter
|
||||||
|
|
@ -66,9 +66,10 @@ class OnboardingWalletFragment :
|
||||||
|
|
||||||
internal val bindingSeedPhrase: LayoutOnboardingSeedPhraseBinding by lazy { binding.onboardingSeedPhraseContainer }
|
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
|
||||||
|
|
||||||
private val seedPhraseStateHandler: OnboardingSeedPhraseStateHandler = OnboardingSeedPhraseStateHandler()
|
|
||||||
private val seedPhraseViewModel by viewModels<SeedPhraseViewModel>()
|
private val seedPhraseViewModel by viewModels<SeedPhraseViewModel>()
|
||||||
|
|
||||||
private lateinit var cardsWidget: WalletCardsWidget
|
private lateinit var cardsWidget: WalletCardsWidget
|
||||||
|
|
@ -79,6 +80,7 @@ class OnboardingWalletFragment :
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
seedPhraseStateHandler = OnboardingSeedPhraseStateHandler(activity = requireActivity())
|
||||||
|
|
||||||
val newSeedPhraseRouter = makeSeedPhraseRouter()
|
val newSeedPhraseRouter = makeSeedPhraseRouter()
|
||||||
seedPhraseRouter = newSeedPhraseRouter
|
seedPhraseRouter = newSeedPhraseRouter
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,22 @@ package com.tangem.tap.features.saveWallet.redux
|
||||||
import com.tangem.common.*
|
import com.tangem.common.*
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.extensions.guard
|
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.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.builder.UserWalletBuilder
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
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.AnalyticsParam
|
||||||
import com.tangem.tap.common.analytics.events.MainScreen
|
import com.tangem.tap.common.analytics.events.MainScreen
|
||||||
import com.tangem.tap.common.analytics.events.Onboarding
|
import com.tangem.tap.common.analytics.events.Onboarding
|
||||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
import com.tangem.tap.common.extensions.*
|
||||||
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.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import com.tangem.tap.mainScope
|
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
import com.tangem.tap.scope
|
|
||||||
import com.tangem.tap.store
|
|
||||||
import com.tangem.tap.tangemSdkManager
|
|
||||||
import com.tangem.utils.coroutines.JobHolder
|
import com.tangem.utils.coroutines.JobHolder
|
||||||
import com.tangem.utils.coroutines.saveIn
|
import com.tangem.utils.coroutines.saveIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.rekotlin.Middleware
|
import org.rekotlin.Middleware
|
||||||
import org.rekotlin.Store
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal class SaveWalletMiddleware {
|
internal class SaveWalletMiddleware {
|
||||||
|
|
@ -83,12 +76,12 @@ internal class SaveWalletMiddleware {
|
||||||
Timber.e(error, "Unable to save user wallet")
|
Timber.e(error, "Unable to save user wallet")
|
||||||
}
|
}
|
||||||
.doOnSuccess { mainScope.launch { store.onUserWalletSelected(userWallet) } }
|
.doOnSuccess { mainScope.launch { store.onUserWalletSelected(userWallet) } }
|
||||||
.doOnResult { store.navigateToWallet() }
|
.doOnResult { navigateToWallet() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enrollBiometrics() {
|
private fun enrollBiometrics() {
|
||||||
store.dispatchOnMain(NavigationAction.OpenBiometricsSettings)
|
activityResultCaller.openSystemBiometrySettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun allowToUseBiometrics(state: SaveWalletState) {
|
private fun allowToUseBiometrics(state: SaveWalletState) {
|
||||||
|
|
@ -133,7 +126,7 @@ internal class SaveWalletMiddleware {
|
||||||
)
|
)
|
||||||
|
|
||||||
store.dispatchWithMain(SaveWalletAction.AllowToUseBiometrics.Success)
|
store.dispatchWithMain(SaveWalletAction.AllowToUseBiometrics.Success)
|
||||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dismiss(state: SaveWalletState) {
|
private fun dismiss(state: SaveWalletState) {
|
||||||
|
|
@ -162,13 +155,9 @@ internal class SaveWalletMiddleware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Store<AppState>.navigateToWallet() {
|
private fun navigateToWallet() {
|
||||||
dispatchWithMain(
|
store.dispatchNavigationAction {
|
||||||
if (store.state.navigationState.backStack.contains(AppScreen.Wallet)) {
|
replaceAll(AppRoute.Wallet)
|
||||||
NavigationAction.PopBackTo(AppScreen.Wallet)
|
}
|
||||||
} else {
|
|
||||||
NavigationAction.NavigateTo(AppScreen.Wallet)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import com.tangem.blockchain.common.FeePaidCurrency
|
||||||
import com.tangem.blockchain.common.WalletManager
|
import com.tangem.blockchain.common.WalletManager
|
||||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.core.navigation.StateDialog
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.tap.common.analytics.events.Token.Send.AddressEntered
|
import com.tangem.tap.common.analytics.events.Token.Send.AddressEntered
|
||||||
import com.tangem.tap.common.redux.ToastNotificationAction
|
import com.tangem.tap.common.redux.ToastNotificationAction
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@ import com.tangem.blockchain.common.transaction.Fee
|
||||||
import com.tangem.blockchain.extensions.Result
|
import com.tangem.blockchain.extensions.Result
|
||||||
import com.tangem.blockchainsdk.utils.minimalAmount
|
import com.tangem.blockchainsdk.utils.minimalAmount
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.core.analytics.Analytics
|
import com.tangem.core.analytics.Analytics
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||||
import com.tangem.domain.common.extensions.withMainContext
|
import com.tangem.domain.common.extensions.withMainContext
|
||||||
import com.tangem.domain.demo.DemoTransactionSender
|
import com.tangem.domain.demo.DemoTransactionSender
|
||||||
|
|
@ -270,7 +270,7 @@ private fun sendTransaction(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
Analytics.sendSelectedCurrencyEvent(mainCurrencyType)
|
Analytics.sendSelectedCurrencyEvent(mainCurrencyType)
|
||||||
dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Result.Failure -> {
|
is Result.Failure -> {
|
||||||
|
|
@ -326,7 +326,7 @@ private fun sendTransaction(
|
||||||
AppDialog.SimpleOkDialogRes(
|
AppDialog.SimpleOkDialogRes(
|
||||||
headerId = R.string.common_done,
|
headerId = R.string.common_done,
|
||||||
messageId = R.string.alert_demo_feature_disabled,
|
messageId = R.string.alert_demo_feature_disabled,
|
||||||
onOk = { dispatch(NavigationAction.PopBackTo()) },
|
onOk = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.tangem.tap.features.send.redux.reducers
|
package com.tangem.tap.features.send.redux.reducers
|
||||||
|
|
||||||
import com.tangem.common.Strings.STARS
|
|
||||||
import com.tangem.common.extensions.isZero
|
import com.tangem.common.extensions.isZero
|
||||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||||
import com.tangem.tap.features.send.redux.AmountAction
|
import com.tangem.tap.features.send.redux.AmountAction
|
||||||
|
|
@ -11,6 +10,7 @@ import com.tangem.tap.features.send.redux.states.AmountState
|
||||||
import com.tangem.tap.features.send.redux.states.InputViewValue
|
import com.tangem.tap.features.send.redux.states.InputViewValue
|
||||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||||
import com.tangem.tap.features.send.redux.states.SendState
|
import com.tangem.tap.features.send.redux.states.SendState
|
||||||
|
import com.tangem.utils.Strings.STARS
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import com.tangem.blockchain.common.Amount
|
||||||
import com.tangem.blockchain.common.AmountType
|
import com.tangem.blockchain.common.AmountType
|
||||||
import com.tangem.blockchain.common.WalletManager
|
import com.tangem.blockchain.common.WalletManager
|
||||||
import com.tangem.common.extensions.isZero
|
import com.tangem.common.extensions.isZero
|
||||||
import com.tangem.core.navigation.StateDialog
|
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.redux.StateDialog
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.tap.common.CurrencyConverter
|
import com.tangem.tap.common.CurrencyConverter
|
||||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import android.text.method.DigitsKeyListener
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import androidx.core.view.postDelayed
|
import androidx.core.view.postDelayed
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
|
@ -20,19 +19,18 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.tangem.Message
|
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.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.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.qrscanning.models.SourceType
|
import com.tangem.domain.qrscanning.models.SourceType
|
||||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||||
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
|
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
|
||||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
|
||||||
import com.tangem.sdk.extensions.hideSoftKeyboard
|
import com.tangem.sdk.extensions.hideSoftKeyboard
|
||||||
import com.tangem.tap.common.KeyboardObserver
|
import com.tangem.tap.common.KeyboardObserver
|
||||||
import com.tangem.tap.common.analytics.events.Token
|
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.getFromClipboard
|
||||||
import com.tangem.tap.common.extensions.setOnImeActionListener
|
import com.tangem.tap.common.extensions.setOnImeActionListener
|
||||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||||
|
|
@ -162,14 +160,9 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
||||||
imvQrCode.setOnClickListener {
|
imvQrCode.setOnClickListener {
|
||||||
Analytics.send(Token.Send.ButtonQRCode())
|
Analytics.send(Token.Send.ButtonQRCode())
|
||||||
|
|
||||||
store.dispatchOnMain(
|
store.dispatchNavigationAction {
|
||||||
NavigationAction.NavigateTo(
|
push(AppRoute.QrScanning(source = SourceType.SEND))
|
||||||
screen = AppScreen.QrScanning,
|
}
|
||||||
bundle = bundleOf(
|
|
||||||
QrScanningRouter.SOURCE_KEY to SourceType.SEND,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,7 +363,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
val externalTransactionData = store.state.sendState.externalTransactionData
|
val externalTransactionData = store.state.sendState.externalTransactionData
|
||||||
if (externalTransactionData == null) {
|
if (externalTransactionData == null) {
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
} else {
|
} else {
|
||||||
store.dispatch(TradeCryptoAction.FinishSelling(externalTransactionData.transactionId))
|
store.dispatch(TradeCryptoAction.FinishSelling(externalTransactionData.transactionId))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.features.send.ui
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||||
import com.tangem.domain.qrscanning.models.SourceType
|
import com.tangem.domain.qrscanning.models.SourceType
|
||||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
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.tokens.model.Network
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
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.common.analytics.events.Token
|
||||||
import com.tangem.tap.di.DelayedWork
|
import com.tangem.tap.di.DelayedWork
|
||||||
import com.tangem.tap.features.send.redux.AddressActionUi
|
import com.tangem.tap.features.send.redux.AddressActionUi
|
||||||
|
|
@ -52,7 +52,7 @@ internal class SendViewModel @Inject constructor(
|
||||||
.launchIn(viewModelScope)
|
.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) {
|
override fun onCreate(owner: LifecycleOwner) {
|
||||||
getBalanceHidingSettingsUseCase()
|
getBalanceHidingSettingsUseCase()
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
package com.tangem.tap.features.tokens.impl.presentation
|
package com.tangem.tap.features.tokens.impl.presentation
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.systemBarsPadding
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import com.tangem.core.ui.UiDependencies
|
import com.tangem.core.ui.UiDependencies
|
||||||
import com.tangem.core.ui.components.SystemBarsEffect
|
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
|
||||||
import com.tangem.core.ui.screen.ComposeFragment
|
import com.tangem.core.ui.screen.ComposeFragment
|
||||||
import com.tangem.tap.features.tokens.impl.presentation.ui.TokensListScreen
|
import com.tangem.tap.features.tokens.impl.presentation.ui.TokensListScreen
|
||||||
import com.tangem.tap.features.tokens.impl.presentation.viewmodels.TokensListViewModel
|
import com.tangem.tap.features.tokens.impl.presentation.viewmodels.TokensListViewModel
|
||||||
|
|
@ -30,12 +27,7 @@ internal class TokensListFragment : ComposeFragment() {
|
||||||
val viewModel = hiltViewModel<TokensListViewModel>().apply {
|
val viewModel = hiltViewModel<TokensListViewModel>().apply {
|
||||||
LocalLifecycleOwner.current.lifecycle.addObserver(this)
|
LocalLifecycleOwner.current.lifecycle.addObserver(this)
|
||||||
}
|
}
|
||||||
val statusBarColor = TangemTheme.colors.background.secondary
|
|
||||||
SystemBarsEffect {
|
|
||||||
setSystemBarsColor(color = statusBarColor)
|
|
||||||
}
|
|
||||||
TokensListScreen(
|
TokensListScreen(
|
||||||
modifier = Modifier.systemBarsPadding(),
|
|
||||||
stateHolder = viewModel.uiState,
|
stateHolder = viewModel.uiState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package com.tangem.tap.features.tokens.impl.presentation.router
|
package com.tangem.tap.features.tokens.impl.presentation.router
|
||||||
|
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
import com.tangem.common.routing.AppRouter
|
||||||
|
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
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.extensions.dispatchNotification
|
||||||
import com.tangem.tap.common.redux.AppDialog
|
import com.tangem.tap.common.redux.AppDialog
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -18,11 +20,11 @@ import com.tangem.wallet.R
|
||||||
internal class DefaultTokensListRouter : TokensListRouter {
|
internal class DefaultTokensListRouter : TokensListRouter {
|
||||||
|
|
||||||
override fun popBackStack() {
|
override fun popBackStack() {
|
||||||
store.dispatch(NavigationAction.PopBackTo())
|
store.dispatchNavigationAction(AppRouter::pop)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openAddCustomTokenScreen() {
|
override fun openAddCustomTokenScreen() {
|
||||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddCustomToken))
|
store.dispatchNavigationAction { push(AppRoute.AddCustomToken) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showAddressCopiedNotification() {
|
override fun showAddressCopiedNotification() {
|
||||||
|
|
@ -54,7 +56,7 @@ internal class DefaultTokensListRouter : TokensListRouter {
|
||||||
val alert = AppDialog.SimpleOkDialogRes(
|
val alert = AppDialog.SimpleOkDialogRes(
|
||||||
headerId = R.string.common_error,
|
headerId = R.string.common_error,
|
||||||
messageId = R.string.common_unknown_error,
|
messageId = R.string.common_unknown_error,
|
||||||
onOk = { store.dispatch(NavigationAction.PopBackTo()) },
|
onOk = { store.dispatchNavigationAction(AppRouter::pop) },
|
||||||
)
|
)
|
||||||
store.dispatchDialogShow(alert)
|
store.dispatchDialogShow(alert)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import androidx.compose.material.Scaffold
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
|
@ -34,6 +33,8 @@ import androidx.paging.compose.LazyPagingItems
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import androidx.paging.compose.itemContentType
|
import androidx.paging.compose.itemContentType
|
||||||
import androidx.paging.compose.itemKey
|
import androidx.paging.compose.itemKey
|
||||||
|
import com.tangem.core.ui.components.BottomFade
|
||||||
|
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||||
import com.tangem.core.ui.components.PrimaryButton
|
import com.tangem.core.ui.components.PrimaryButton
|
||||||
import com.tangem.core.ui.res.TangemThemePreview
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
@ -61,32 +62,45 @@ internal fun TokensListScreen(stateHolder: TokensListStateHolder, modifier: Modi
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = { TokensListToolbar(state = stateHolder.toolbarState) },
|
topBar = {
|
||||||
|
TokensListToolbar(state = stateHolder.toolbarState)
|
||||||
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
if (stateHolder is TokensListStateHolder.ManageContent) {
|
if (stateHolder is TokensListStateHolder.ManageContent) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val verticalPadding = TangemTheme.dimens.spacing32
|
val verticalPadding = TangemTheme.dimens.spacing32
|
||||||
|
|
||||||
SaveChangesButton(
|
SaveChangesButton(
|
||||||
modifier = Modifier.onSizeChanged {
|
modifier = Modifier
|
||||||
with(density) { floatingButtonHeight = it.height.toDp() + verticalPadding }
|
.navigationBarsPadding()
|
||||||
},
|
.onSizeChanged {
|
||||||
|
with(density) { floatingButtonHeight = it.height.toDp() + verticalPadding }
|
||||||
|
},
|
||||||
showProgress = stateHolder.isSavingInProgress,
|
showProgress = stateHolder.isSavingInProgress,
|
||||||
onClick = stateHolder.onSaveButtonClick,
|
onClick = stateHolder.onSaveButtonClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
floatingActionButtonPosition = FabPosition.Center,
|
floatingActionButtonPosition = FabPosition.Center,
|
||||||
backgroundColor = TangemTheme.colors.background.primary,
|
backgroundColor = TangemTheme.colors.background.secondary,
|
||||||
) { scaffoldPadding ->
|
) { _ ->
|
||||||
val tokens = stateHolder.tokens.collectAsLazyPagingItems()
|
val tokens = stateHolder.tokens.collectAsLazyPagingItems()
|
||||||
|
|
||||||
TokensListContent(
|
if (stateHolder !is TokensListStateHolder.ManageContent) {
|
||||||
isDifferentAddressesBlockVisible = stateHolder.isDifferentAddressesBlockVisible,
|
NavigationBar3ButtonsScrim()
|
||||||
tokens = tokens,
|
}
|
||||||
scaffoldPadding = scaffoldPadding,
|
|
||||||
bottomMarginDp = floatingButtonHeight,
|
Box {
|
||||||
)
|
TokensListContent(
|
||||||
|
isDifferentAddressesBlockVisible = stateHolder.isDifferentAddressesBlockVisible,
|
||||||
|
tokens = tokens,
|
||||||
|
bottomMarginDp = floatingButtonHeight,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (stateHolder is TokensListStateHolder.ManageContent) {
|
||||||
|
BottomFade(Modifier.align(Alignment.BottomCenter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Crossfade(targetState = stateHolder.isLoading, label = "Update progress bar visibility") {
|
Crossfade(targetState = stateHolder.isLoading, label = "Update progress bar visibility") {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
|
@ -112,23 +126,24 @@ private fun LoadingContent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TokensListContent(
|
private fun TokensListContent(
|
||||||
isDifferentAddressesBlockVisible: Boolean,
|
isDifferentAddressesBlockVisible: Boolean,
|
||||||
tokens: LazyPagingItems<TokenItemState>,
|
tokens: LazyPagingItems<TokenItemState>,
|
||||||
scaffoldPadding: PaddingValues,
|
|
||||||
bottomMarginDp: Dp,
|
bottomMarginDp: Dp,
|
||||||
) {
|
) {
|
||||||
val state = rememberLazyListState()
|
val state = rememberLazyListState()
|
||||||
|
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.background(color = TangemTheme.colors.background.primary)
|
||||||
.imePadding()
|
.imePadding()
|
||||||
.fillMaxSize()
|
.fillMaxSize(),
|
||||||
.padding(scaffoldPadding),
|
|
||||||
state = state,
|
state = state,
|
||||||
contentPadding = PaddingValues(bottom = bottomMarginDp),
|
contentPadding = PaddingValues(
|
||||||
|
bottom = bottomMarginDp + bottomBarHeight,
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
item(
|
item(
|
||||||
key = "DifferentAddressesWarning$isDifferentAddressesBlockVisible",
|
key = "DifferentAddressesWarning$isDifferentAddressesBlockVisible",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
package com.tangem.tap.features.tokens.impl.presentation.ui
|
package com.tangem.tap.features.tokens.impl.presentation.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
|
@ -16,6 +13,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -42,8 +40,15 @@ internal fun TokensListToolbar(state: TokensListToolbarState) {
|
||||||
} else {
|
} else {
|
||||||
AppBarDefaults.TopAppBarElevation
|
AppBarDefaults.TopAppBarElevation
|
||||||
}
|
}
|
||||||
|
val statusBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getTop(this).toDp() }
|
||||||
|
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
backgroundColor = TangemTheme.colors.background.secondary,
|
backgroundColor = TangemTheme.colors.background.secondary,
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
start = TangemTheme.dimens.spacing4,
|
||||||
|
end = TangemTheme.dimens.spacing4,
|
||||||
|
top = statusBarHeight,
|
||||||
|
),
|
||||||
elevation = toolbarElevation,
|
elevation = toolbarElevation,
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = state.onBackButtonClick) {
|
IconButton(onClick = state.onBackButtonClick) {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package com.tangem.tap.features.tokens.impl.presentation.viewmodels
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.blockchain.common.Token
|
import com.tangem.blockchain.common.Token
|
||||||
import com.tangem.core.navigation.AppScreen
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.core.navigation.NavigationAction
|
import com.tangem.common.routing.utils.popTo
|
||||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
import com.tangem.domain.card.DerivePublicKeysUseCase
|
||||||
import com.tangem.domain.common.util.derivationStyleProvider
|
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.models.UserWalletId
|
||||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
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.common.extensions.inject
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
|
@ -126,7 +126,7 @@ internal class TokensListMigration(
|
||||||
val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty()
|
val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty()
|
||||||
if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) {
|
if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) {
|
||||||
store.dispatchDebugErrorNotification(message = "Nothing to save")
|
store.dispatchDebugErrorNotification(message = "Nothing to save")
|
||||||
store.dispatchWithMain(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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