Updated on 2026-08-14
This commit is contained in:
commit
3debe69f54
903 changed files with 22403 additions and 10801 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) {
|
||||||
|
|
|
||||||
4
app/src/debug/res/values/values.xml
Normal file
4
app/src/debug/res/values/values.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<bool name="resizeable_activity">true</bool>
|
||||||
|
</resources>
|
||||||
4
app/src/external/res/values/values.xml
vendored
Normal file
4
app/src/external/res/values/values.xml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<bool name="resizeable_activity">true</bool>
|
||||||
|
</resources>
|
||||||
4
app/src/internal/res/values/values.xml
Normal file
4
app/src/internal/res/values/values.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<bool name="resizeable_activity">true</bool>
|
||||||
|
</resources>
|
||||||
|
|
@ -40,11 +40,11 @@
|
||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:resizeableActivity="@bool/resizeable_activity"
|
||||||
android:label="@string/tangem_app_name"
|
android:label="@string/tangem_app_name"
|
||||||
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">
|
||||||
|
|
@ -146,5 +146,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
|
||||||
|
|
@ -15,6 +18,7 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||||
import com.tangem.domain.card.ScanCardProcessor
|
import com.tangem.domain.card.ScanCardProcessor
|
||||||
import com.tangem.domain.card.repository.CardRepository
|
import com.tangem.domain.card.repository.CardRepository
|
||||||
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
||||||
|
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||||
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||||
|
|
@ -26,9 +30,8 @@ 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.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
|
||||||
|
|
@ -59,8 +62,6 @@ interface ApplicationEntryPoint {
|
||||||
|
|
||||||
fun getWalletConnectSessionsRepository(): WalletConnectSessionsRepository
|
fun getWalletConnectSessionsRepository(): WalletConnectSessionsRepository
|
||||||
|
|
||||||
fun getManageTokensFeatureToggles(): ManageTokensFeatureToggles
|
|
||||||
|
|
||||||
fun getScanCardProcessor(): ScanCardProcessor
|
fun getScanCardProcessor(): ScanCardProcessor
|
||||||
|
|
||||||
fun getAppCurrencyRepository(): AppCurrencyRepository
|
fun getAppCurrencyRepository(): AppCurrencyRepository
|
||||||
|
|
@ -109,5 +110,13 @@ interface ApplicationEntryPoint {
|
||||||
|
|
||||||
fun getDetailsFeatureToggles(): DetailsFeatureToggles
|
fun getDetailsFeatureToggles(): DetailsFeatureToggles
|
||||||
|
|
||||||
fun getDetailsEntryPoint(): DetailsEntryPoint
|
fun getGetCardInfoUseCase(): GetCardInfoUseCase
|
||||||
|
|
||||||
|
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,40 +1,41 @@
|
||||||
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.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.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.AppRouter
|
||||||
|
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
|
||||||
|
|
@ -43,6 +44,7 @@ import com.tangem.core.ui.res.TangemColorPalette
|
||||||
import com.tangem.data.card.sdk.CardSdkOwner
|
import com.tangem.data.card.sdk.CardSdkOwner
|
||||||
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
|
||||||
|
|
@ -50,8 +52,9 @@ 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.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
|
||||||
|
|
@ -62,6 +65,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
|
||||||
|
|
@ -71,17 +77,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
|
||||||
|
|
||||||
|
|
@ -128,9 +134,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var tokenDetailsRouter: TokenDetailsRouter
|
lateinit var tokenDetailsRouter: TokenDetailsRouter
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var manageTokensUi: ManageTokensUi
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var walletConnectInteractor: WalletConnectInteractor
|
lateinit var walletConnectInteractor: WalletConnectInteractor
|
||||||
|
|
||||||
|
|
@ -161,6 +164,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
|
||||||
|
internal lateinit var appRouter: AppRouter
|
||||||
|
|
||||||
|
@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>
|
||||||
|
|
@ -180,6 +205,13 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
|
|
||||||
val splashScreen = installSplashScreen()
|
val splashScreen = installSplashScreen()
|
||||||
|
|
||||||
|
enableEdgeToEdge(
|
||||||
|
navigationBarStyle = SystemBarStyle.auto(
|
||||||
|
Color.Transparent.toArgb(),
|
||||||
|
Color.Transparent.toArgb(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
splashScreen.setKeepOnScreenCondition { viewModel.isSplashScreenShown }
|
splashScreen.setKeepOnScreenCondition { viewModel.isSplashScreenShown }
|
||||||
|
|
@ -188,9 +220,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()
|
||||||
|
|
||||||
|
|
@ -199,6 +231,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)
|
||||||
|
|
@ -220,8 +277,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installActivityDependencies() {
|
private fun installActivityDependencies() {
|
||||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
|
||||||
|
|
||||||
cardSdkOwner.register(activity = this)
|
cardSdkOwner.register(activity = this)
|
||||||
tangemSdkManager = injectedTangemSdkManager
|
tangemSdkManager = injectedTangemSdkManager
|
||||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||||
|
|
@ -241,11 +296,12 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
walletRouter = walletRouter,
|
walletRouter = walletRouter,
|
||||||
walletConnectInteractor = walletConnectInteractor,
|
walletConnectInteractor = walletConnectInteractor,
|
||||||
tokenDetailsRouter = tokenDetailsRouter,
|
tokenDetailsRouter = tokenDetailsRouter,
|
||||||
manageTokensUi = manageTokensUi,
|
|
||||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||||
sendRouter = sendRouter,
|
sendRouter = sendRouter,
|
||||||
qrScanningRouter = qrScanningRouter,
|
qrScanningRouter = qrScanningRouter,
|
||||||
emailSender = emailSender,
|
emailSender = emailSender,
|
||||||
|
stakingRouter = stakingRouter,
|
||||||
|
pushNotificationsRouter = pushNotificationsRouter,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -266,8 +322,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,
|
||||||
|
|
@ -298,19 +352,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)
|
||||||
|
|
||||||
|
|
@ -319,8 +375,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() {
|
||||||
|
|
@ -330,7 +389,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
store.dispatch(NavigationAction.ActivityDestroyed(WeakReference(this)))
|
|
||||||
intentProcessor.removeAll()
|
intentProcessor.removeAll()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
@ -470,8 +528,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
||||||
val backStack = store.state.navigationState.backStack
|
val backStack = appRouter.stack
|
||||||
val isOnInitialScreen = backStack.all { it == AppScreen.Welcome || it == AppScreen.Home }
|
val isOnInitialScreen = backStack.all { it is AppRoute.Welcome || it is AppRoute.Home }
|
||||||
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
||||||
val isOnboardingServiceNotActive = !store.state.globalState.onboardingState.onboardingStarted
|
val isOnboardingServiceNotActive = !store.state.globalState.onboardingState.onboardingStarted
|
||||||
|
|
||||||
|
|
@ -488,17 +546,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -506,16 +563,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
|
||||||
|
|
@ -32,6 +33,7 @@ import com.tangem.domain.card.ScanCardProcessor
|
||||||
import com.tangem.domain.card.repository.CardRepository
|
import com.tangem.domain.card.repository.CardRepository
|
||||||
import com.tangem.domain.common.LogConfig
|
import com.tangem.domain.common.LogConfig
|
||||||
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
||||||
|
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||||
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||||
|
|
@ -43,9 +45,8 @@ 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.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
|
||||||
|
|
@ -110,9 +111,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
private val walletConnectSessionsRepository: WalletConnectSessionsRepository
|
private val walletConnectSessionsRepository: WalletConnectSessionsRepository
|
||||||
get() = entryPoint.getWalletConnectSessionsRepository()
|
get() = entryPoint.getWalletConnectSessionsRepository()
|
||||||
|
|
||||||
private val manageTokensFeatureToggles: ManageTokensFeatureToggles
|
|
||||||
get() = entryPoint.getManageTokensFeatureToggles()
|
|
||||||
|
|
||||||
private val scanCardProcessor: ScanCardProcessor
|
private val scanCardProcessor: ScanCardProcessor
|
||||||
get() = entryPoint.getScanCardProcessor()
|
get() = entryPoint.getScanCardProcessor()
|
||||||
|
|
||||||
|
|
@ -181,13 +179,25 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
|
|
||||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase
|
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase
|
||||||
get() = entryPoint.getSaveBlockchainErrorUseCase()
|
get() = entryPoint.getSaveBlockchainErrorUseCase()
|
||||||
// endregion
|
|
||||||
|
private val getCardInfoUseCase: GetCardInfoUseCase
|
||||||
|
get() = entryPoint.getGetCardInfoUseCase()
|
||||||
|
|
||||||
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()
|
||||||
|
|
@ -253,7 +263,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
customTokenFeatureToggles = customTokenFeatureToggles,
|
customTokenFeatureToggles = customTokenFeatureToggles,
|
||||||
walletConnectRepository = walletConnect2Repository,
|
walletConnectRepository = walletConnect2Repository,
|
||||||
walletConnectSessionsRepository = walletConnectSessionsRepository,
|
walletConnectSessionsRepository = walletConnectSessionsRepository,
|
||||||
manageTokensFeatureToggles = manageTokensFeatureToggles,
|
|
||||||
scanCardProcessor = scanCardProcessor,
|
scanCardProcessor = scanCardProcessor,
|
||||||
appCurrencyRepository = appCurrencyRepository,
|
appCurrencyRepository = appCurrencyRepository,
|
||||||
walletManagersFacade = walletManagersFacade,
|
walletManagersFacade = walletManagersFacade,
|
||||||
|
|
@ -274,9 +283,14 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
blockchainSDKFactory = blockchainSDKFactory,
|
blockchainSDKFactory = blockchainSDKFactory,
|
||||||
saveBlockchainErrorUseCase = saveBlockchainErrorUseCase,
|
saveBlockchainErrorUseCase = saveBlockchainErrorUseCase,
|
||||||
detailsFeatureToggles = detailsFeatureToggles,
|
getFeedbackEmailUseCase = getFeedbackEmailUseCase,
|
||||||
detailsEntryPoint = detailsEntryPoint,
|
getCardInfoUseCase = getCardInfoUseCase,
|
||||||
assetLoader = assetLoader,
|
assetLoader = assetLoader,
|
||||||
|
detailsFeatureToggles = detailsFeatureToggles,
|
||||||
|
urlOpener = urlOpener,
|
||||||
|
shareManager = shareManager,
|
||||||
|
appRouter = appRouter,
|
||||||
|
pushNotificationsFeatureToggles = pushNotificationsFeatureToggles,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -365,7 +379,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)
|
||||||
}
|
}
|
||||||
|
|
@ -7,13 +7,14 @@ import com.tangem.domain.common.TapWorkarounds
|
||||||
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
import com.tangem.domain.feedback.FeedbackManagerFeatureToggles
|
||||||
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||||
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.tap.common.chat.ChatManager
|
import com.tangem.tap.common.chat.ChatManager
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.common.extensions.sendEmail
|
import com.tangem.tap.common.extensions.sendEmail
|
||||||
import com.tangem.tap.common.log.TangemLogCollector
|
import com.tangem.tap.common.log.TangemLogCollector
|
||||||
import com.tangem.tap.foregroundActivityObserver
|
import com.tangem.tap.foregroundActivityObserver
|
||||||
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.store
|
||||||
import com.tangem.tap.withForegroundActivity
|
import com.tangem.tap.withForegroundActivity
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -25,7 +26,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,
|
||||||
|
|
@ -36,16 +37,24 @@ class FeedbackManager(
|
||||||
private var sessionFeedbackFile: File? = null
|
private var sessionFeedbackFile: File? = null
|
||||||
private var sessionLogsFile: File? = null
|
private var sessionLogsFile: File? = null
|
||||||
|
|
||||||
fun sendEmail(feedbackData: FeedbackData, onFail: ((Exception) -> Unit)? = null) {
|
fun sendEmail(feedbackData: FeedbackData, scanResponse: ScanResponse?) {
|
||||||
if (feedbackManagerFeatureToggles.isLocalLogsEnabled) {
|
if (feedbackManagerFeatureToggles.isLocalLogsEnabled) {
|
||||||
mainScope.launch {
|
scope.launch {
|
||||||
|
val getCardInfo = suspend {
|
||||||
|
scanResponse ?: error("ScanResponse must be not null")
|
||||||
|
store.inject(DaggerGraphState::getCardInfoUseCase).invoke(scanResponse).getOrNull()
|
||||||
|
?: error("CardInfo must be not null")
|
||||||
|
}
|
||||||
|
|
||||||
val email = getFeedbackEmailUseCase(
|
val email = getFeedbackEmailUseCase(
|
||||||
when (feedbackData) {
|
type = when (feedbackData) {
|
||||||
is FeedbackEmail -> FeedbackEmailType.DirectUserRequest
|
is FeedbackEmail -> FeedbackEmailType.DirectUserRequest(cardInfo = getCardInfo())
|
||||||
is RateCanBeBetterEmail -> FeedbackEmailType.RateCanBeBetter
|
is RateCanBeBetterEmail -> FeedbackEmailType.RateCanBeBetter(cardInfo = getCardInfo())
|
||||||
is ScanFailsEmail -> FeedbackEmailType.ScanningProblem
|
is ScanFailsEmail -> FeedbackEmailType.ScanningProblem
|
||||||
is SendTransactionFailedEmail -> FeedbackEmailType.TransactionSendingProblem
|
is SendTransactionFailedEmail -> {
|
||||||
else -> FeedbackEmailType.DirectUserRequest
|
FeedbackEmailType.TransactionSendingProblem(cardInfo = getCardInfo())
|
||||||
|
}
|
||||||
|
else -> FeedbackEmailType.DirectUserRequest(cardInfo = getCardInfo())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -66,12 +75,28 @@ class FeedbackManager(
|
||||||
subject = activity.getString(feedbackData.subjectResId),
|
subject = activity.getString(feedbackData.subjectResId),
|
||||||
message = feedbackData.joinTogether(activity, infoHolder),
|
message = feedbackData.joinTogether(activity, infoHolder),
|
||||||
file = getLogFile(activity),
|
file = getLogFile(activity),
|
||||||
onFail = onFail,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sendEmail(type: FeedbackEmailType) {
|
||||||
|
if (!feedbackManagerFeatureToggles.isLocalLogsEnabled) error("LOCAL_LOGS feature toggle must be enabled")
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
val email = getFeedbackEmailUseCase(type = type)
|
||||||
|
|
||||||
|
store.inject(DaggerGraphState::emailSender).send(
|
||||||
|
email = EmailSender.Email(
|
||||||
|
address = email.address,
|
||||||
|
subject = email.subject,
|
||||||
|
message = email.message,
|
||||||
|
attachment = email.file,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun openChat(config: ChatConfig, feedbackData: FeedbackData) {
|
fun openChat(config: ChatConfig, feedbackData: FeedbackData) {
|
||||||
chatManager.open(
|
chatManager.open(
|
||||||
config = config,
|
config = config,
|
||||||
|
|
@ -144,7 +169,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,20 @@
|
||||||
|
package com.tangem.tap.common.feedback
|
||||||
|
|
||||||
|
import com.tangem.domain.feedback.FeedbackManager
|
||||||
|
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||||
|
import com.tangem.tap.store
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
internal class ProxyFeedbackManager : FeedbackManager {
|
||||||
|
|
||||||
|
override fun sendEmail(type: FeedbackEmailType) {
|
||||||
|
val manager = store.state.globalState.feedbackManager
|
||||||
|
|
||||||
|
if (manager == null) {
|
||||||
|
Timber.e("Feedback manager is not initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.sendEmail(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,9 +79,9 @@ 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, val scanResponse: ScanResponse?) : GlobalAction()
|
||||||
data class OpenChat(val feedbackData: FeedbackData, val chatConfig: ChatConfig? = null) : GlobalAction()
|
data class OpenChat(val feedbackData: FeedbackData, val chatConfig: ChatConfig? = null) : GlobalAction()
|
||||||
|
|
||||||
object ExchangeManager : GlobalAction() {
|
object ExchangeManager : 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
|
||||||
|
|
@ -69,7 +69,10 @@ private fun handleAction(action: Action, appState: () -> AppState?) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is GlobalAction.SendEmail -> {
|
is GlobalAction.SendEmail -> {
|
||||||
store.state.globalState.feedbackManager?.sendEmail(action.feedbackData)
|
store.state.globalState.feedbackManager?.sendEmail(
|
||||||
|
feedbackData = action.feedbackData,
|
||||||
|
scanResponse = action.scanResponse,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is GlobalAction.OpenChat -> {
|
is GlobalAction.OpenChat -> {
|
||||||
val globalState = store.state.globalState
|
val globalState = store.state.globalState
|
||||||
|
|
|
||||||
|
|
@ -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,8 +1,11 @@
|
||||||
package com.tangem.tap.common.redux.legacy
|
package com.tangem.tap.common.redux.legacy
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.AmountType
|
||||||
|
import com.tangem.domain.feedback.models.BlockchainErrorInfo
|
||||||
import com.tangem.domain.redux.LegacyAction
|
import com.tangem.domain.redux.LegacyAction
|
||||||
import com.tangem.domain.tokens.utils.convertToAmount
|
import com.tangem.domain.tokens.utils.convertToAmount
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
|
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||||
import com.tangem.tap.common.feedback.RateCanBeBetterEmail
|
import com.tangem.tap.common.feedback.RateCanBeBetterEmail
|
||||||
import com.tangem.tap.common.feedback.SendTransactionFailedEmail
|
import com.tangem.tap.common.feedback.SendTransactionFailedEmail
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
|
|
@ -19,7 +22,10 @@ internal object LegacyMiddleware {
|
||||||
{ action ->
|
{ action ->
|
||||||
when (action) {
|
when (action) {
|
||||||
is LegacyAction.SendEmailRateCanBeBetter -> {
|
is LegacyAction.SendEmailRateCanBeBetter -> {
|
||||||
store.state.globalState.feedbackManager?.sendEmail(RateCanBeBetterEmail())
|
store.state.globalState.feedbackManager?.sendEmail(
|
||||||
|
feedbackData = RateCanBeBetterEmail(),
|
||||||
|
scanResponse = action.scanResponse,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is LegacyAction.StartOnboardingProcess -> {
|
is LegacyAction.StartOnboardingProcess -> {
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
|
|
@ -28,8 +34,28 @@ internal object LegacyMiddleware {
|
||||||
}
|
}
|
||||||
is LegacyAction.SendEmailTransactionFailed -> {
|
is LegacyAction.SendEmailTransactionFailed -> {
|
||||||
if (store.inject(DaggerGraphState::feedbackManagerFeatureToggles).isLocalLogsEnabled) {
|
if (store.inject(DaggerGraphState::feedbackManagerFeatureToggles).isLocalLogsEnabled) {
|
||||||
|
|
||||||
|
val amount = action.amount?.convertToAmount(action.cryptoCurrency)
|
||||||
|
store.inject(DaggerGraphState::saveBlockchainErrorUseCase).invoke(
|
||||||
|
error = BlockchainErrorInfo(
|
||||||
|
errorMessage = action.errorMessage,
|
||||||
|
blockchainId = action.cryptoCurrency.network.id.value,
|
||||||
|
derivationPath = action.cryptoCurrency.network.derivationPath.value,
|
||||||
|
destinationAddress = action.destinationAddress.orEmpty(),
|
||||||
|
tokenSymbol = if (amount?.type is AmountType.Token) {
|
||||||
|
amount.currencySymbol
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
},
|
||||||
|
amount = amount?.value?.stripZeroPlainString() ?: "unknown",
|
||||||
|
fee = action.fee?.convertToAmount(action.cryptoCurrency)
|
||||||
|
?.value?.stripZeroPlainString() ?: "unknown",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
store.state.globalState.feedbackManager?.sendEmail(
|
store.state.globalState.feedbackManager?.sendEmail(
|
||||||
SendTransactionFailedEmail(action.errorMessage),
|
feedbackData = SendTransactionFailedEmail(action.errorMessage),
|
||||||
|
scanResponse = action.scanResponse,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|
@ -46,7 +72,8 @@ internal object LegacyMiddleware {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
store.state.globalState.feedbackManager?.sendEmail(
|
store.state.globalState.feedbackManager?.sendEmail(
|
||||||
SendTransactionFailedEmail(action.errorMessage),
|
feedbackData = SendTransactionFailedEmail(action.errorMessage),
|
||||||
|
scanResponse = 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
|
||||||
Analytics.send(Basic.ButtonSupport(sourceAnalytics))
|
StateDialog.ScanFailsSource.INTRO -> AnalyticsParam.ScreensSources.Intro
|
||||||
store.dispatch(GlobalAction.SendEmail(ScanFailsEmail()))
|
|
||||||
}
|
}
|
||||||
setNeutralButton(R.string.common_cancel) { _, _ -> }
|
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))
|
||||||
|
store.dispatch(GlobalAction.SendEmail(feedbackData = ScanFailsEmail(), scanResponse = null))
|
||||||
|
}
|
||||||
|
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(
|
||||||
|
|
@ -4,6 +4,7 @@ import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
|
|
||||||
// FIXME: Workaround, remove it once the normal UserWalletsStore has been implemented
|
// FIXME: Workaround, remove it once the normal UserWalletsStore has been implemented
|
||||||
|
|
@ -15,6 +16,9 @@ internal class RuntimeUserWalletsStore(
|
||||||
override val selectedUserWalletOrNull: UserWallet?
|
override val selectedUserWalletOrNull: UserWallet?
|
||||||
get() = userWalletsListManager.selectedUserWalletSync
|
get() = userWalletsListManager.selectedUserWalletSync
|
||||||
|
|
||||||
|
override val userWallets: Flow<List<UserWallet>>
|
||||||
|
get() = userWalletsListManager.userWallets
|
||||||
|
|
||||||
override suspend fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
override suspend fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
||||||
return userWalletsListManager
|
return userWalletsListManager
|
||||||
.userWallets
|
.userWallets
|
||||||
|
|
|
||||||
|
|
@ -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.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.domain.feedback.FeedbackManager
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.tangem.tap.di.domain
|
package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||||
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
import com.tangem.domain.feedback.GetFeedbackEmailUseCase
|
||||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||||
import com.tangem.domain.feedback.repository.FeedbackRepository
|
import com.tangem.domain.feedback.repository.FeedbackRepository
|
||||||
|
|
@ -15,6 +16,12 @@ import javax.inject.Singleton
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
internal object FeedbackDomainModule {
|
internal object FeedbackDomainModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetCardInfoUseCase(feedbackRepository: FeedbackRepository): GetCardInfoUseCase {
|
||||||
|
return GetCardInfoUseCase(feedbackRepository = feedbackRepository)
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetFeedbackEmailUseCase(
|
fun provideGetFeedbackEmailUseCase(
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package com.tangem.tap.di.domain
|
package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.domain.settings.*
|
import com.tangem.domain.staking.*
|
||||||
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
|
||||||
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
|
|
||||||
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 +12,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,9 +30,35 @@ internal object StakingDomainModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetStakingAvailabilityUseCase(stakingRepository: StakingRepository): GetStakingAvailabilityUseCase {
|
fun provideGetYieldUseCase(stakingRepository: StakingRepository): GetYieldUseCase {
|
||||||
return GetStakingAvailabilityUseCase(
|
return GetYieldUseCase(
|
||||||
stakingRepository = stakingRepository,
|
stakingRepository = stakingRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetStakingTokensUseCase(stakingRepository: StakingRepository): FetchStakingTokensUseCase {
|
||||||
|
return FetchStakingTokensUseCase(
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideFetchStakingYieldBalanceUseCase(stakingRepository: StakingRepository): FetchStakingYieldBalanceUseCase {
|
||||||
|
return FetchStakingYieldBalanceUseCase(stakingRepository = stakingRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetStakingYieldBalanceUseCase(stakingRepository: StakingRepository): GetStakingYieldBalanceUseCase {
|
||||||
|
return GetStakingYieldBalanceUseCase(stakingRepository = stakingRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideCreateEnterActionUseCase(stakingRepository: StakingRepository): InitializeStakingProcessUseCase {
|
||||||
|
return InitializeStakingProcessUseCase(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
|
||||||
|
|
@ -54,8 +55,14 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
): GetTokenListUseCase {
|
): GetTokenListUseCase {
|
||||||
return GetTokenListUseCase(currenciesRepository, quotesRepository, networksRepository)
|
return GetTokenListUseCase(
|
||||||
|
currenciesRepository,
|
||||||
|
quotesRepository,
|
||||||
|
networksRepository,
|
||||||
|
stakingRepository,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -64,8 +71,9 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
): GetCardTokensListUseCase {
|
): GetCardTokensListUseCase {
|
||||||
return GetCardTokensListUseCase(currenciesRepository, quotesRepository, networksRepository)
|
return GetCardTokensListUseCase(currenciesRepository, quotesRepository, networksRepository, stakingRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -83,9 +91,16 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetCurrencyStatusUpdatesUseCase {
|
): GetCurrencyStatusUpdatesUseCase {
|
||||||
return GetCurrencyStatusUpdatesUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
return GetCurrencyStatusUpdatesUseCase(
|
||||||
|
currenciesRepository,
|
||||||
|
quotesRepository,
|
||||||
|
networksRepository,
|
||||||
|
stakingRepository,
|
||||||
|
dispatchers,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -100,6 +115,7 @@ internal object TokensDomainModule {
|
||||||
currencyChecksRepository: CurrencyChecksRepository,
|
currencyChecksRepository: CurrencyChecksRepository,
|
||||||
showSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase,
|
showSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase,
|
||||||
promoRepository: PromoRepository,
|
promoRepository: PromoRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetCurrencyWarningsUseCase {
|
): GetCurrencyWarningsUseCase {
|
||||||
return GetCurrencyWarningsUseCase(
|
return GetCurrencyWarningsUseCase(
|
||||||
|
|
@ -112,6 +128,7 @@ internal object TokensDomainModule {
|
||||||
swapRepository = swapRepository,
|
swapRepository = swapRepository,
|
||||||
showSwapPromoTokenUseCase = showSwapPromoTokenUseCase,
|
showSwapPromoTokenUseCase = showSwapPromoTokenUseCase,
|
||||||
promoRepository = promoRepository,
|
promoRepository = promoRepository,
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -122,12 +139,14 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetPrimaryCurrencyStatusUpdatesUseCase {
|
): GetPrimaryCurrencyStatusUpdatesUseCase {
|
||||||
return GetPrimaryCurrencyStatusUpdatesUseCase(
|
return GetPrimaryCurrencyStatusUpdatesUseCase(
|
||||||
currenciesRepository,
|
currenciesRepository,
|
||||||
quotesRepository,
|
quotesRepository,
|
||||||
networksRepository,
|
networksRepository,
|
||||||
|
stakingRepository,
|
||||||
dispatchers,
|
dispatchers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -148,8 +167,9 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
): FetchCardTokenListUseCase {
|
): FetchCardTokenListUseCase {
|
||||||
return FetchCardTokenListUseCase(currenciesRepository, networksRepository, quotesRepository)
|
return FetchCardTokenListUseCase(currenciesRepository, networksRepository, quotesRepository, stakingRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -190,6 +210,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 +220,7 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
quotesRepository = quotesRepository,
|
quotesRepository = quotesRepository,
|
||||||
networksRepository = networksRepository,
|
networksRepository = networksRepository,
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -209,12 +231,14 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetNetworkCoinStatusUseCase {
|
): GetNetworkCoinStatusUseCase {
|
||||||
return GetNetworkCoinStatusUseCase(
|
return GetNetworkCoinStatusUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
quotesRepository = quotesRepository,
|
quotesRepository = quotesRepository,
|
||||||
networksRepository = networksRepository,
|
networksRepository = networksRepository,
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -225,12 +249,14 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetFeePaidCryptoCurrencyStatusSyncUseCase {
|
): GetFeePaidCryptoCurrencyStatusSyncUseCase {
|
||||||
return GetFeePaidCryptoCurrencyStatusSyncUseCase(
|
return GetFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
quotesRepository = quotesRepository,
|
quotesRepository = quotesRepository,
|
||||||
networksRepository = networksRepository,
|
networksRepository = networksRepository,
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -363,11 +389,13 @@ internal object TokensDomainModule {
|
||||||
currenciesRepository: CurrenciesRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
|
stakingRepository: StakingRepository,
|
||||||
): GetWalletTotalBalanceUseCase {
|
): GetWalletTotalBalanceUseCase {
|
||||||
return GetWalletTotalBalanceUseCase(
|
return GetWalletTotalBalanceUseCase(
|
||||||
currenciesRepository = currenciesRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
quotesRepository = quotesRepository,
|
quotesRepository = quotesRepository,
|
||||||
networksRepository = networksRepository,
|
networksRepository = networksRepository,
|
||||||
|
stakingRepository = stakingRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,20 @@ internal object TransactionDomainModule {
|
||||||
return CreateTransactionUseCase(transactionRepository)
|
return CreateTransactionUseCase(transactionRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideCreateTransactionExtrasUseCase(
|
||||||
|
transactionRepository: TransactionRepository,
|
||||||
|
): CreateTransactionDataExtrasUseCase {
|
||||||
|
return CreateTransactionDataExtrasUseCase(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,7 +5,7 @@ import com.tangem.blockchain.common.TransactionStatus
|
||||||
import com.tangem.blockchain.common.Wallet
|
import com.tangem.blockchain.common.Wallet
|
||||||
|
|
||||||
data class PendingTransaction(
|
data class PendingTransaction(
|
||||||
val transactionData: TransactionData,
|
val transactionData: TransactionData.Uncompiled,
|
||||||
val type: PendingTransactionType,
|
val type: PendingTransactionType,
|
||||||
) {
|
) {
|
||||||
val address: String? = when (type) {
|
val address: String? = when (type) {
|
||||||
|
|
@ -21,7 +21,7 @@ data class PendingTransaction(
|
||||||
|
|
||||||
enum class PendingTransactionType { Incoming, Outgoing, Unknown }
|
enum class PendingTransactionType { Incoming, Outgoing, Unknown }
|
||||||
|
|
||||||
fun TransactionData.toPendingTransaction(walletAddress: String): PendingTransaction? {
|
fun TransactionData.Uncompiled.toPendingTransaction(walletAddress: String): PendingTransaction? {
|
||||||
if (this.status == TransactionStatus.Confirmed) return null
|
if (this.status == TransactionStatus.Confirmed) return null
|
||||||
|
|
||||||
val type: PendingTransactionType = when {
|
val type: PendingTransactionType = when {
|
||||||
|
|
@ -32,7 +32,7 @@ fun TransactionData.toPendingTransaction(walletAddress: String): PendingTransact
|
||||||
return PendingTransaction(this, type)
|
return PendingTransaction(this, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<TransactionData>.toPendingTransactions(walletAddress: String): List<PendingTransaction> {
|
fun List<TransactionData.Uncompiled>.toPendingTransactions(walletAddress: String): List<PendingTransaction> {
|
||||||
return this.mapNotNull { it.toPendingTransaction(walletAddress) }
|
return this.mapNotNull { it.toPendingTransaction(walletAddress) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
@ -91,9 +91,8 @@ class WalletConnectSdkHelper {
|
||||||
|
|
||||||
val destinationAddress = requireNotNull(transaction.to) { "Destination address is null" }
|
val destinationAddress = requireNotNull(transaction.to) { "Destination address is null" }
|
||||||
|
|
||||||
val transactionData = TransactionData(
|
val transactionData = TransactionData.Uncompiled(
|
||||||
amount = Amount(value, wallet.blockchain),
|
amount = Amount(value, wallet.blockchain),
|
||||||
// TODO refactoring
|
|
||||||
fee = Fee.Common(Amount(fee, wallet.blockchain)),
|
fee = Fee.Common(Amount(fee, wallet.blockchain)),
|
||||||
sourceAddress = transaction.from,
|
sourceAddress = transaction.from,
|
||||||
destinationAddress = destinationAddress,
|
destinationAddress = destinationAddress,
|
||||||
|
|
|
||||||
|
|
@ -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,5 +1,6 @@
|
||||||
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.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -8,7 +9,6 @@ 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.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
|
||||||
|
|
@ -32,15 +32,12 @@ 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
AddCustomTokenScreen(
|
AddCustomTokenScreen(
|
||||||
modifier = Modifier.systemBarsPadding(),
|
modifier = Modifier
|
||||||
|
.background(TangemTheme.colors.background.primary)
|
||||||
|
.systemBarsPadding(),
|
||||||
stateHolder = state,
|
stateHolder = state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,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
|
||||||
|
|
@ -19,6 +21,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.*
|
||||||
|
|
@ -29,9 +32,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
|
||||||
|
|
@ -71,7 +71,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)
|
||||||
|
|
@ -91,7 +92,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 -> {
|
||||||
|
|
@ -132,15 +133,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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +165,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
|
||||||
|
|
@ -183,7 +184,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 -> {
|
||||||
|
|
@ -243,6 +244,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +274,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) {
|
||||||
|
|
@ -393,7 +395,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)
|
||||||
}
|
}
|
||||||
|
|
@ -432,7 +434,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 {
|
||||||
|
|
@ -444,7 +446,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),
|
||||||
)
|
)
|
||||||
|
|
@ -500,7 +502,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)
|
||||||
|
|
@ -544,7 +546,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) {
|
||||||
|
|
@ -552,7 +554,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
|
||||||
|
|
@ -66,10 +66,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
|
||||||
|
|
@ -279,6 +281,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) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ internal sealed class SettingsItem(
|
||||||
data class CardSettings(
|
data class CardSettings(
|
||||||
override val onClick: () -> Unit,
|
override val onClick: () -> Unit,
|
||||||
) : SettingsItem(
|
) : SettingsItem(
|
||||||
iconResId = R.drawable.ic_card_settings,
|
iconResId = R.drawable.ic_card_settings_24,
|
||||||
title = resourceReference(R.string.card_settings_title),
|
title = resourceReference(R.string.card_settings_title),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ internal sealed class SettingsItem(
|
||||||
data class ReferralProgram(
|
data class ReferralProgram(
|
||||||
override val onClick: () -> Unit,
|
override val onClick: () -> Unit,
|
||||||
) : SettingsItem(
|
) : SettingsItem(
|
||||||
iconResId = R.drawable.ic_add_friends,
|
iconResId = R.drawable.ic_add_friends_24,
|
||||||
title = resourceReference(R.string.details_referral_title),
|
title = resourceReference(R.string.details_referral_title),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,30 +127,38 @@ 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() {
|
||||||
Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Settings))
|
Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Settings))
|
||||||
store.dispatchOnMain(GlobalAction.SendEmail(FeedbackEmail()))
|
store.dispatchOnMain(
|
||||||
|
GlobalAction.SendEmail(
|
||||||
|
feedbackData = FeedbackEmail(),
|
||||||
|
scanResponse = userWalletsListManager.selectedUserWalletSync?.scanResponse
|
||||||
|
?: error("ScanResponse must be not null"),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +171,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 +181,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,9 +2,9 @@ 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.common.routing.AppRoute
|
||||||
|
import com.tangem.common.routing.utils.popTo
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.navigation.AppScreen
|
|
||||||
import com.tangem.core.navigation.NavigationAction
|
|
||||||
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.common.util.cardTypesResolver
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
|
|
@ -16,6 +16,7 @@ import com.tangem.domain.wallets.legacy.asLockable
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
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.tap.common.extensions.dispatchNavigationAction
|
||||||
import com.tangem.tap.common.analytics.events.Settings
|
import com.tangem.tap.common.analytics.events.Settings
|
||||||
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
|
||||||
|
|
@ -190,13 +191,13 @@ internal class ResetCardViewModel @Inject constructor(
|
||||||
val newSelectedWallet = userWalletsListManager.selectedUserWalletSync
|
val newSelectedWallet = userWalletsListManager.selectedUserWalletSync
|
||||||
|
|
||||||
if (newSelectedWallet != null) {
|
if (newSelectedWallet != null) {
|
||||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Wallet))
|
store.dispatchNavigationAction { popTo<AppRoute.Wallet>() }
|
||||||
} else {
|
} else {
|
||||||
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }.isSuccess
|
val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync }.isSuccess
|
||||||
if (isLocked && userWalletsListManager.hasUserWallets) {
|
if (isLocked && userWalletsListManager.hasUserWallets) {
|
||||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Welcome))
|
store.dispatchNavigationAction { popTo<AppRoute.Welcome>() }
|
||||||
} 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,10 @@ 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 +15,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 +35,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 +45,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 +73,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 +122,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 +151,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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,20 @@ import androidx.core.view.MenuProvider
|
||||||
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.domain.models.scan.ScanResponse
|
||||||
import com.tangem.tap.common.feedback.SupportInfo
|
import com.tangem.tap.common.feedback.SupportInfo
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.tap.common.redux.global.GlobalAction
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
import com.tangem.utils.Provider
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
class OnboardingMenuProvider : MenuProvider {
|
class OnboardingMenuProvider(
|
||||||
|
private val scanResponseProvider: Provider<ScanResponse>,
|
||||||
|
) : MenuProvider {
|
||||||
|
|
||||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
menuInflater.inflate(R.menu.menu_onboarding, menu)
|
menuInflater.inflate(R.menu.menu_onboarding, menu)
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +29,12 @@ class OnboardingMenuProvider : MenuProvider {
|
||||||
R.id.menu_item_chat_support -> {
|
R.id.menu_item_chat_support -> {
|
||||||
Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro))
|
Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro))
|
||||||
// changed on email support [REDACTED_TASK_KEY]
|
// changed on email support [REDACTED_TASK_KEY]
|
||||||
store.dispatch(GlobalAction.SendEmail(SupportInfo()))
|
store.dispatch(
|
||||||
|
GlobalAction.SendEmail(
|
||||||
|
feedbackData = SupportInfo(),
|
||||||
|
scanResponse = scanResponseProvider(),
|
||||||
|
),
|
||||||
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else -> false
|
else -> false
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import com.tangem.tap.common.extensions.show
|
||||||
import com.tangem.tap.common.transitions.HomeToOnboardingTransition
|
import com.tangem.tap.common.transitions.HomeToOnboardingTransition
|
||||||
import com.tangem.tap.features.BaseStoreFragment
|
import com.tangem.tap.features.BaseStoreFragment
|
||||||
import com.tangem.tap.features.onboarding.OnboardingMenuProvider
|
import com.tangem.tap.features.onboarding.OnboardingMenuProvider
|
||||||
|
import com.tangem.tap.store
|
||||||
|
import com.tangem.utils.Provider
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import com.tangem.wallet.databinding.FragmentOnboardingMainBinding
|
import com.tangem.wallet.databinding.FragmentOnboardingMainBinding
|
||||||
import com.tangem.wallet.databinding.ViewOnboardingProgressBinding
|
import com.tangem.wallet.databinding.ViewOnboardingProgressBinding
|
||||||
|
|
@ -32,7 +34,13 @@ abstract class BaseOnboardingFragment<T> : BaseStoreFragment(R.layout.fragment_o
|
||||||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadToolbarMenu(): MenuProvider? = OnboardingMenuProvider()
|
override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider(
|
||||||
|
scanResponseProvider = Provider {
|
||||||
|
store.state.globalState.onboardingState.onboardingManager?.scanResponse
|
||||||
|
?: store.state.detailsState.scanResponse
|
||||||
|
?: error("ScanResponse must be not null")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
protected fun showConfetti(show: Boolean) = with(binding.vConfetti) {
|
protected fun showConfetti(show: Boolean) = with(binding.vConfetti) {
|
||||||
lavConfetti.show(show)
|
lavConfetti.show(show)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.features.onboarding.products.twins.redux
|
package com.tangem.tap.features.onboarding.products.twins.redux
|
||||||
|
|
||||||
import com.tangem.domain.common.util.cardTypesResolver
|
|
||||||
import com.tangem.domain.common.getTwinCardNumber
|
import com.tangem.domain.common.getTwinCardNumber
|
||||||
|
import com.tangem.domain.common.util.cardTypesResolver
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
import org.rekotlin.Action
|
import org.rekotlin.Action
|
||||||
|
|
||||||
|
|
@ -35,7 +35,10 @@ private fun internalReduce(action: Action, state: AppState): TwinCardsState {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is TwinCardsAction.SetStepOfScreen -> {
|
is TwinCardsAction.SetStepOfScreen -> {
|
||||||
state = state.copy(currentStep = action.step)
|
state = state.copy(
|
||||||
|
currentStep = action.step,
|
||||||
|
welcomeOnlyScanResponse = (action.step as? TwinCardsStep.WelcomeOnly)?.scanResponse,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is TwinCardsAction.SetUserUnderstand -> {
|
is TwinCardsAction.SetUserUnderstand -> {
|
||||||
state = state.copy(userWasUnderstandIfWalletRecreate = action.isUnderstand)
|
state = state.copy(userWasUnderstandIfWalletRecreate = action.isUnderstand)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.tap.features.onboarding.products.twins.redux
|
package com.tangem.tap.features.onboarding.products.twins.redux
|
||||||
|
|
||||||
import com.tangem.blockchain.common.WalletManager
|
import com.tangem.blockchain.common.WalletManager
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
|
||||||
import com.tangem.domain.common.TwinCardNumber
|
import com.tangem.domain.common.TwinCardNumber
|
||||||
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.tap.domain.TapError
|
import com.tangem.tap.domain.TapError
|
||||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||||
import com.tangem.tap.features.onboarding.OnboardingWalletBalance
|
import com.tangem.tap.features.onboarding.OnboardingWalletBalance
|
||||||
|
|
@ -29,6 +29,7 @@ data class TwinCardsState(
|
||||||
val balanceNonCriticalError: TapError? = null,
|
val balanceNonCriticalError: TapError? = null,
|
||||||
val balanceCriticalError: TapError? = null,
|
val balanceCriticalError: TapError? = null,
|
||||||
val showConfetti: Boolean = false,
|
val showConfetti: Boolean = false,
|
||||||
|
val welcomeOnlyScanResponse: ScanResponse? = null,
|
||||||
) : StateType {
|
) : StateType {
|
||||||
|
|
||||||
val steps: List<TwinCardsStep>
|
val steps: List<TwinCardsStep>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import android.view.View
|
||||||
import android.view.animation.OvershootInterpolator
|
import android.view.animation.OvershootInterpolator
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.constraintlayout.widget.ConstraintSet
|
import androidx.constraintlayout.widget.ConstraintSet
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
import coil.load
|
import coil.load
|
||||||
|
|
@ -25,12 +26,14 @@ import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget
|
||||||
import com.tangem.tap.common.transitions.InternalNoteLayoutTransition
|
import com.tangem.tap.common.transitions.InternalNoteLayoutTransition
|
||||||
import com.tangem.tap.domain.twins.TwinsCardWidget
|
import com.tangem.tap.domain.twins.TwinsCardWidget
|
||||||
import com.tangem.tap.features.addBackPressHandler
|
import com.tangem.tap.features.addBackPressHandler
|
||||||
|
import com.tangem.tap.features.onboarding.OnboardingMenuProvider
|
||||||
import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment
|
import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment
|
||||||
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.features.onboarding.products.twins.redux.TwinCardsState
|
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
|
import com.tangem.utils.Provider
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding
|
import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
@ -61,6 +64,15 @@ internal class OnboardingTwinsFragment : BaseOnboardingFragment<TwinCardsState>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider(
|
||||||
|
scanResponseProvider = Provider {
|
||||||
|
store.state.twinCardsState.welcomeOnlyScanResponse
|
||||||
|
?: store.state.globalState.onboardingState.onboardingManager?.scanResponse
|
||||||
|
?: store.state.detailsState.scanResponse
|
||||||
|
?: error("ScanResponse must be not null")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
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