Updated on 2026-08-14
This commit is contained in:
parent
56956a0c2b
commit
b73d93928b
22 changed files with 292 additions and 264 deletions
|
|
@ -1,12 +0,0 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
|
||||
internal sealed class GlobalSettingsState {
|
||||
|
||||
object Loading : GlobalSettingsState()
|
||||
|
||||
data class Content(
|
||||
val appThemeMode: AppThemeMode,
|
||||
) : GlobalSettingsState()
|
||||
}
|
||||
|
|
@ -1,18 +1,20 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import android.app.Application
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
|
|
@ -32,7 +34,6 @@ import com.tangem.tap.common.DialogManager
|
|||
import com.tangem.tap.common.OnActivityResultCallback
|
||||
import com.tangem.tap.common.SnackbarHandler
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.NotificationsHandler
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.shop.googlepay.GooglePayService
|
||||
|
|
@ -49,19 +50,15 @@ import com.tangem.tap.features.intentHandler.handlers.SellCurrencyIntentHandler
|
|||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.features.shop.redux.ShopAction
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
import com.tangem.tap.features.welcome.ui.WelcomeFragment
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.ActivityMainBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
|
@ -117,8 +114,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
lateinit var walletConnectInteractor: WalletConnectInteractor
|
||||
|
||||
private val viewModel: MainViewModel by viewModels()
|
||||
private var isInitializing: Boolean = true
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode?>
|
||||
|
||||
// TODO: fixme: inject through DI
|
||||
private val intentProcessor: IntentProcessor = IntentProcessor()
|
||||
|
|
@ -130,25 +126,24 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
private val onActivityResultCallbacks = mutableListOf<OnActivityResultCallback>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
|
||||
if (!isDarkThemeFeatureEnabled(application)) {
|
||||
setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
}
|
||||
installSplashScreen()
|
||||
installAppTheme() // We need to call it before onCreate to prevent unnecessary activity recreation
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
|
||||
bootstrapMainStateUpdates(application)
|
||||
|
||||
splashScreen.setKeepOnScreenCondition { isInitializing }
|
||||
installActivityDependencies()
|
||||
observeAppThemeModeUpdates()
|
||||
|
||||
setContentView(R.layout.activity_main)
|
||||
systemActions()
|
||||
initContent()
|
||||
|
||||
checkGooglePayAvailability()
|
||||
}
|
||||
|
||||
private fun installActivityDependencies() {
|
||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
||||
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
tangemSdkManager = injectedTangemSdkManager
|
||||
appStateHolder.tangemSdkManager = tangemSdkManager
|
||||
backupService = BackupService.init(cardSdkConfigRepository.sdk, this)
|
||||
|
|
@ -157,11 +152,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
initUserWalletsListManager()
|
||||
initIntentHandlers()
|
||||
|
||||
store.dispatch(
|
||||
ShopAction.CheckIfGooglePayAvailable(
|
||||
GooglePayService(createPaymentsClient(this), this),
|
||||
),
|
||||
)
|
||||
store.dispatch(
|
||||
DaggerGraphAction.SetActivityDependencies(
|
||||
testerRouter = testerRouter,
|
||||
|
|
@ -174,9 +164,57 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
)
|
||||
}
|
||||
|
||||
private fun isDarkThemeFeatureEnabled(application: Application): Boolean {
|
||||
val featureToggle = (application as TapApplication).darkThemeFeatureToggle
|
||||
return featureToggle.isDarkThemeEnabled
|
||||
private fun installAppTheme() {
|
||||
appThemeModeFlow = createAppThemeModeFlow()
|
||||
val mode = runBlocking { appThemeModeFlow.filterNotNull().first() }
|
||||
|
||||
updateAppTheme(mode)
|
||||
}
|
||||
|
||||
private fun observeAppThemeModeUpdates() {
|
||||
appThemeModeFlow
|
||||
.filterNotNull()
|
||||
.flowWithLifecycle(lifecycle)
|
||||
.onEach(::updateAppTheme)
|
||||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
private fun initContent() {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
|
||||
supportFragmentManager.registerFragmentLifecycleCallbacks(
|
||||
NavBarInsetsFragmentLifecycleCallback(),
|
||||
true,
|
||||
)
|
||||
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
|
||||
private fun checkGooglePayAvailability() {
|
||||
store.dispatch(
|
||||
ShopAction.CheckIfGooglePayAvailable(
|
||||
GooglePayService(createPaymentsClient(this), this),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createAppThemeModeFlow(): SharedFlow<AppThemeMode?> {
|
||||
val tapApplication = application as TapApplication
|
||||
val featureToggle = tapApplication.darkThemeFeatureToggle
|
||||
|
||||
return if (featureToggle.isDarkThemeEnabled) {
|
||||
tapApplication.getAppThemeModeUseCase()
|
||||
.map { maybeMode ->
|
||||
maybeMode.getOrElse { AppThemeMode.DEFAULT }
|
||||
}
|
||||
.shareIn(
|
||||
scope = lifecycleScope + Dispatchers.IO,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5_000),
|
||||
)
|
||||
} else {
|
||||
MutableStateFlow(AppThemeMode.FORCE_LIGHT)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
@ -189,7 +227,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
// TODO: RESEARCH! NotificationsHandler is created in onResume and destroyed in onStop
|
||||
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
|
||||
|
||||
navigateToInitialScreenIfNeededOnResume(intent)
|
||||
navigateToInitialScreenIfNeeded(intent)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
|
|
@ -207,12 +245,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
private fun initIntentHandlers() {
|
||||
val hasSavedWalletsProvider = { store.state.globalState.userWalletsListManager?.hasUserWallets == true }
|
||||
intentProcessor.addHandler(
|
||||
BackgroundScanIntentHandler(
|
||||
hasSavedWalletsProvider,
|
||||
lifecycleScope,
|
||||
),
|
||||
)
|
||||
intentProcessor.addHandler(BackgroundScanIntentHandler(hasSavedWalletsProvider, lifecycleScope))
|
||||
intentProcessor.addHandler(WalletConnectLinkIntentHandler())
|
||||
intentProcessor.addHandler(BuyCurrencyIntentHandler())
|
||||
intentProcessor.addHandler(SellCurrencyIntentHandler())
|
||||
|
|
@ -230,38 +263,21 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
store.dispatch(GlobalAction.UpdateUserWalletsListManager(manager))
|
||||
}
|
||||
|
||||
private fun bootstrapMainStateUpdates(application: Application) {
|
||||
viewModel.state
|
||||
.onEach { state ->
|
||||
isInitializing = state is GlobalSettingsState.Loading
|
||||
private fun updateAppTheme(appThemeMode: AppThemeMode) {
|
||||
MutableAppThemeModeHolder.value = appThemeMode
|
||||
MutableAppThemeModeHolder.isDarkThemeActive = isDarkTheme()
|
||||
|
||||
when (state) {
|
||||
is GlobalSettingsState.Content -> {
|
||||
if (isDarkThemeFeatureEnabled(application)) {
|
||||
MutableAppThemeModeHolder.value = state.appThemeMode
|
||||
MutableAppThemeModeHolder.isDarkThemeActive = isDarkTheme()
|
||||
val mode = when (appThemeMode) {
|
||||
AppThemeMode.FORCE_DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
AppThemeMode.FORCE_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
AppThemeMode.FOLLOW_SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
|
||||
val mode = when (state.appThemeMode) {
|
||||
AppThemeMode.FORCE_DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
AppThemeMode.FORCE_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
AppThemeMode.FOLLOW_SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
setDefaultNightMode(mode)
|
||||
} else {
|
||||
MutableAppThemeModeHolder.value = AppThemeMode.FORCE_LIGHT
|
||||
}
|
||||
}
|
||||
is GlobalSettingsState.Loading -> Unit
|
||||
}
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
setDefaultNightMode(mode)
|
||||
}
|
||||
|
||||
private fun isDarkTheme(): Boolean {
|
||||
return when (
|
||||
resources.configuration.uiMode and
|
||||
Configuration.UI_MODE_NIGHT_MASK
|
||||
) {
|
||||
return when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||
Configuration.UI_MODE_NIGHT_YES -> true
|
||||
Configuration.UI_MODE_NIGHT_NO -> false
|
||||
Configuration.UI_MODE_NIGHT_UNDEFINED -> false
|
||||
|
|
@ -269,17 +285,6 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
}
|
||||
}
|
||||
|
||||
private fun systemActions() {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
|
||||
supportFragmentManager.registerFragmentLifecycleCallbacks(
|
||||
NavBarInsetsFragmentLifecycleCallback(),
|
||||
true,
|
||||
)
|
||||
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
|
|
@ -341,43 +346,40 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
lockUserWalletsTimer?.restart()
|
||||
}
|
||||
|
||||
private fun navigateToInitialScreenIfNeededOnResume(intentWhichStartedActivity: Intent?) {
|
||||
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
||||
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
||||
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
||||
val isOnboardingServiceNotActive = store.state.globalState.onboardingState.onboardingStarted
|
||||
val isShopNotOpened = store.state.shopState.total != null
|
||||
|
||||
when {
|
||||
!backStackIsEmpty && isNotScannedBefore && isOnboardingServiceNotActive && isShopNotOpened -> {
|
||||
navigateToInitialScreenOnResume(intentWhichStartedActivity)
|
||||
navigateToInitialScreen(intentWhichStartedActivity)
|
||||
}
|
||||
backStackIsEmpty -> {
|
||||
navigateToInitialScreenOnResume(intentWhichStartedActivity)
|
||||
navigateToInitialScreen(intentWhichStartedActivity)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToInitialScreenOnResume(intentWhichStartedActivity: Intent?) {
|
||||
private fun navigateToInitialScreen(intentWhichStartedActivity: Intent?) {
|
||||
if (store.state.globalState.userWalletsListManager?.hasUserWallets == true) {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Welcome))
|
||||
store.dispatchOnMain(WelcomeAction.SetInitialIntent(intentWhichStartedActivity))
|
||||
lifecycleScope.launch {
|
||||
val handler = BackgroundScanIntentHandler(
|
||||
hasSavedUserWalletsProvider = { true },
|
||||
lifecycleCoroutineScope = lifecycleScope,
|
||||
)
|
||||
val isBackgroundScanHandled = handler.handleIntent(intentWhichStartedActivity)
|
||||
val hasNotIncompletedBackup = !backupService.hasIncompletedBackup
|
||||
if (!isBackgroundScanHandled && hasNotIncompletedBackup) {
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics)
|
||||
}
|
||||
}
|
||||
store.dispatch(
|
||||
NavigationAction.NavigateTo(
|
||||
screen = AppScreen.Welcome,
|
||||
bundle = intentWhichStartedActivity?.let {
|
||||
bundleOf(WelcomeFragment.INITIAL_INTENT_KEY to it)
|
||||
},
|
||||
),
|
||||
)
|
||||
} else {
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
|
||||
lifecycleScope.launch {
|
||||
intentProcessor.handleIntent(intentWhichStartedActivity)
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class MainViewModel @Inject constructor(
|
||||
private val getAppThemeModeUseCase: GetAppThemeModeUseCase,
|
||||
) : ViewModel() {
|
||||
|
||||
val state: StateFlow<GlobalSettingsState> = createMainStateFlow()
|
||||
|
||||
private fun createMainStateFlow(): StateFlow<GlobalSettingsState> {
|
||||
return getAppThemeModeUseCase()
|
||||
.map { maybeMode ->
|
||||
val mode = maybeMode.getOrElse { AppThemeMode.DEFAULT }
|
||||
|
||||
GlobalSettingsState.Content(appThemeMode = mode)
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5_000),
|
||||
initialValue = GlobalSettingsState.Loading,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import com.tangem.datasource.config.models.Config
|
|||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.datasource.local.token.UserTokensStore
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
|
||||
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
|
|
@ -200,6 +201,9 @@ internal class TapApplication : Application(), ImageLoaderFactory {
|
|||
|
||||
@Inject
|
||||
lateinit var appRatingRepository: AppRatingRepository
|
||||
|
||||
@Inject
|
||||
lateinit var getAppThemeModeUseCase: GetAppThemeModeUseCase
|
||||
// endregion Injected
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AppThemeDomainModule {
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class TangemSdkManager(
|
|||
get() = tangemSdk.authenticationManager.canAuthenticate || needEnrollBiometrics
|
||||
|
||||
val needEnrollBiometrics: Boolean
|
||||
get() = tangemSdk.authenticationManager.canEnrollBiometrics
|
||||
get() = tangemSdk.authenticationManager.needEnrollBiometrics
|
||||
|
||||
val keystoreManager: KeystoreManager
|
||||
get() = tangemSdk.keystoreManager
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
|
|||
Analytics.send(IntroductionProcess.ButtonScanCard())
|
||||
lifecycleScope.launch {
|
||||
store.dispatch(
|
||||
HomeAction.ReadCard(lifecycleCoroutineScope = lifecycleScope),
|
||||
HomeAction.ReadCard(scope = this),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class HomeAction : Action {
|
||||
|
|
@ -23,7 +23,7 @@ sealed class HomeAction : Action {
|
|||
*/
|
||||
data class ReadCard(
|
||||
val analyticsEvent: AnalyticsEvent? = Basic.CardWasScanned(AnalyticsParam.ScannedFrom.Introduction),
|
||||
val lifecycleCoroutineScope: LifecycleCoroutineScope,
|
||||
val scope: CoroutineScope,
|
||||
) : HomeAction()
|
||||
|
||||
data class ScanInProgress(val scanInProgress: Boolean) : HomeAction()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnResult
|
||||
import com.tangem.common.doOnSuccess
|
||||
|
|
@ -63,7 +62,9 @@ private fun handleHomeAction(action: Action) {
|
|||
store.dispatch(GlobalAction.FetchUserCountry)
|
||||
}
|
||||
is HomeAction.ReadCard -> {
|
||||
readCard(action.analyticsEvent, action.lifecycleCoroutineScope)
|
||||
action.scope.launch {
|
||||
readCard(action.analyticsEvent)
|
||||
}
|
||||
}
|
||||
is HomeAction.GoToShop -> {
|
||||
Analytics.send(Shop.ScreenOpened())
|
||||
|
|
@ -78,34 +79,31 @@ private fun handleHomeAction(action: Action) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun readCard(analyticsEvent: AnalyticsEvent?, lifecycleCoroutineScope: LifecycleCoroutineScope) {
|
||||
lifecycleCoroutineScope.launch {
|
||||
delay(timeMillis = 200)
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes,
|
||||
)
|
||||
private suspend fun readCard(analyticsEvent: AnalyticsEvent?) {
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes,
|
||||
)
|
||||
|
||||
store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsEvent = analyticsEvent,
|
||||
onProgressStateChange = { showProgress ->
|
||||
if (showProgress) {
|
||||
changeButtonState(ButtonState.PROGRESS)
|
||||
} else {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
}
|
||||
},
|
||||
onScanStateChange = { scanInProgress ->
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress))
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Unable to scan card")
|
||||
store.state.daggerGraphState.get(DaggerGraphState::scanCardProcessor).scan(
|
||||
analyticsEvent = analyticsEvent,
|
||||
onProgressStateChange = { showProgress ->
|
||||
if (showProgress) {
|
||||
changeButtonState(ButtonState.PROGRESS)
|
||||
} else {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
},
|
||||
onSuccess = { scanResponse ->
|
||||
proceedWithScanResponse(scanResponse)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onScanStateChange = { scanInProgress ->
|
||||
store.dispatch(HomeAction.ScanInProgress(scanInProgress))
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Unable to scan card")
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
},
|
||||
onSuccess = { scanResponse ->
|
||||
proceedWithScanResponse(scanResponse)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch {
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ import android.content.Intent
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface IntentHandler {
|
||||
suspend fun handleIntent(intent: Intent?): Boolean
|
||||
|
||||
fun handleIntent(intent: Intent?): Boolean
|
||||
}
|
||||
|
|
@ -4,21 +4,19 @@ import android.content.Intent
|
|||
import android.nfc.NfcAdapter
|
||||
import android.nfc.Tag
|
||||
import android.os.Build
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.intentHandler.IntentHandler
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class BackgroundScanIntentHandler(
|
||||
private val hasSavedUserWalletsProvider: () -> Boolean,
|
||||
private val lifecycleCoroutineScope: LifecycleCoroutineScope,
|
||||
private val scope: CoroutineScope,
|
||||
) : IntentHandler {
|
||||
|
||||
private val nfcActions = arrayOf(
|
||||
|
|
@ -27,7 +25,7 @@ class BackgroundScanIntentHandler(
|
|||
NfcAdapter.ACTION_TAG_DISCOVERED,
|
||||
)
|
||||
|
||||
override suspend fun handleIntent(intent: Intent?): Boolean {
|
||||
override fun handleIntent(intent: Intent?): Boolean {
|
||||
if (intent == null || intent.action !in nfcActions) return false
|
||||
|
||||
val tag: Tag? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
|
|
@ -40,13 +38,9 @@ class BackgroundScanIntentHandler(
|
|||
|
||||
intent.action = null
|
||||
if (hasSavedUserWalletsProvider.invoke()) {
|
||||
// TODO: Remove delay after [REDACTED_JIRA]
|
||||
lifecycleCoroutineScope.launch {
|
||||
delay(timeMillis = 200)
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard(lifecycleCoroutineScope))
|
||||
}
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard)
|
||||
} else {
|
||||
store.dispatchWithMain(HomeAction.ReadCard(lifecycleCoroutineScope = lifecycleCoroutineScope))
|
||||
store.dispatchOnMain(HomeAction.ReadCard(scope = scope))
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.tangem.tap.store
|
|||
*/
|
||||
class BuyCurrencyIntentHandler : IntentHandler {
|
||||
|
||||
override suspend fun handleIntent(intent: Intent?): Boolean {
|
||||
override fun handleIntent(intent: Intent?): Boolean {
|
||||
val data = intent?.data ?: return false
|
||||
val currency = store.state.walletState.selectedCurrency ?: return false
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.features.intentHandler.handlers
|
|||
|
||||
import android.content.Intent
|
||||
import com.tangem.domain.tokens.legacy.TradeCryptoAction
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.features.intentHandler.IntentHandler
|
||||
import com.tangem.tap.store
|
||||
import timber.log.Timber
|
||||
|
|
@ -12,7 +12,7 @@ import timber.log.Timber
|
|||
*/
|
||||
class SellCurrencyIntentHandler : IntentHandler {
|
||||
|
||||
override suspend fun handleIntent(intent: Intent?): Boolean {
|
||||
override fun handleIntent(intent: Intent?): Boolean {
|
||||
return try {
|
||||
val intentData = intent?.data ?: return false
|
||||
val transactionID = intentData.getQueryParameter(TRANSACTION_ID_PARAM) ?: return false
|
||||
|
|
@ -21,7 +21,7 @@ class SellCurrencyIntentHandler : IntentHandler {
|
|||
val destinationAddress = intentData.getQueryParameter(DEPOSIT_WALLET_ADDRESS_PARAM) ?: return false
|
||||
|
||||
Timber.d("MoonPay Sell: $amount $currency to $destinationAddress")
|
||||
store.dispatchWithMain(
|
||||
store.dispatchOnMain(
|
||||
TradeCryptoAction.SendCrypto(
|
||||
currencyId = currency,
|
||||
amount = amount,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.intentHandler.handlers
|
||||
|
||||
import android.content.Intent
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.removePrefixOrNull
|
||||
import com.tangem.tap.domain.walletconnect.WalletConnectManager
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
|
|
@ -15,7 +15,7 @@ import java.net.URLDecoder
|
|||
*/
|
||||
class WalletConnectLinkIntentHandler : IntentHandler {
|
||||
|
||||
override suspend fun handleIntent(intent: Intent?): Boolean {
|
||||
override fun handleIntent(intent: Intent?): Boolean {
|
||||
val intentData = intent?.data ?: return false
|
||||
val scheme = intent.scheme ?: return false
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ class WalletConnectLinkIntentHandler : IntentHandler {
|
|||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
store.dispatchWithMain(WalletConnectAction.HandleDeepLink(decodedWcUri))
|
||||
store.dispatchOnMain(WalletConnectAction.HandleDeepLink(decodedWcUri))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ private fun handleWalletAction(action: Action) {
|
|||
|
||||
if (scanResponse == null) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(HomeAction.ReadCard(lifecycleCoroutineScope = action.lifecycleCoroutineScope))
|
||||
store.dispatch(HomeAction.ReadCard(scope = action.lifecycleCoroutineScope))
|
||||
} else {
|
||||
val backupState = store.state.onboardingWalletState.backupState
|
||||
val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState)
|
||||
|
|
|
|||
|
|
@ -1,22 +1,27 @@
|
|||
package com.tangem.tap.features.welcome.redux
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.tangem.common.core.TangemError
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.rekotlin.Action
|
||||
|
||||
internal sealed interface WelcomeAction : Action {
|
||||
object ProceedWithBiometrics : WelcomeAction {
|
||||
|
||||
data class SetCoroutineScope(val scope: CoroutineScope) : WelcomeAction
|
||||
|
||||
object ClearCoroutineScope : WelcomeAction
|
||||
|
||||
data class ProceedWithBiometrics(val afterUnlockIntent: Intent? = null) : WelcomeAction {
|
||||
object Success : WelcomeAction
|
||||
data class Error(val error: TangemError) : WelcomeAction
|
||||
}
|
||||
|
||||
data class ProceedWithCard(val lifecycleCoroutineScope: LifecycleCoroutineScope) : WelcomeAction {
|
||||
object ProceedWithCard : WelcomeAction {
|
||||
object Success : WelcomeAction
|
||||
data class Error(val error: TangemError) : WelcomeAction
|
||||
}
|
||||
|
||||
data class SetInitialIntent(val intent: Intent?) : WelcomeAction
|
||||
data class ProceedWithIntent(val intent: Intent) : WelcomeAction
|
||||
|
||||
object CloseError : WelcomeAction
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.features.welcome.redux
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import android.content.Intent
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnResult
|
||||
|
|
@ -18,9 +18,11 @@ import com.tangem.tap.common.extensions.dispatchOnMain
|
|||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
import com.tangem.tap.features.signin.redux.SignInAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
|
|
@ -39,15 +41,94 @@ internal class WelcomeMiddleware {
|
|||
}
|
||||
|
||||
private fun handleAction(action: WelcomeAction, state: WelcomeState) {
|
||||
when (action) {
|
||||
is WelcomeAction.ProceedWithBiometrics -> proceedWithBiometrics(state)
|
||||
is WelcomeAction.ProceedWithCard -> proceedWithCard(state, action.lifecycleCoroutineScope)
|
||||
is WelcomeAction.ClearUserWallets -> disableUserWalletsSaving()
|
||||
else -> Unit
|
||||
state.scope?.launch {
|
||||
when (action) {
|
||||
is WelcomeAction.ProceedWithIntent -> proceedWithIntent(action.intent, scope = this)
|
||||
is WelcomeAction.ProceedWithBiometrics -> proceedWithBiometrics(
|
||||
afterUnlockIntent = action.afterUnlockIntent ?: state.intent,
|
||||
)
|
||||
is WelcomeAction.ProceedWithCard -> proceedWithCard(afterScanIntent = state.intent)
|
||||
is WelcomeAction.ClearUserWallets -> disableUserWalletsSaving()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun disableUserWalletsSaving() = scope.launch {
|
||||
private suspend fun proceedWithIntent(initialIntent: Intent, scope: CoroutineScope) {
|
||||
Timber.d(
|
||||
"""
|
||||
Proceeding with intent
|
||||
|- Intent: $initialIntent
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
val handler = BackgroundScanIntentHandler(
|
||||
scope = scope,
|
||||
hasSavedUserWalletsProvider = { true },
|
||||
)
|
||||
val isBackgroundScanHandled = handler.handleIntent(initialIntent)
|
||||
val hasUncompletedBackup = backupService.hasIncompletedBackup
|
||||
|
||||
if (!isBackgroundScanHandled && !hasUncompletedBackup) {
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics(initialIntent))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun proceedWithBiometrics(afterUnlockIntent: Intent?) {
|
||||
Timber.d(
|
||||
"""
|
||||
Proceeding with biometry
|
||||
|- Intent: $afterUnlockIntent
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
userWalletsListManager.unlockIfLockable()
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to unlock user wallets with biometrics")
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Error(error))
|
||||
}
|
||||
.doOnSuccess { selectedUserWallet ->
|
||||
store.dispatchWithMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Biometric))
|
||||
store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Success)
|
||||
store.onUserWalletSelected(userWallet = selectedUserWallet)
|
||||
|
||||
afterUnlockIntent?.let {
|
||||
WalletConnectLinkIntentHandler().handleIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun proceedWithCard(afterScanIntent: Intent?) {
|
||||
Timber.d(
|
||||
"""
|
||||
Proceeding with card
|
||||
|- Intent: $afterScanIntent
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
scanCardInternal { scanResponse ->
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal
|
||||
|
||||
userWalletsListManager.save(userWallet, canOverride = true)
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to save user wallet")
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Error(error))
|
||||
}
|
||||
.doOnSuccess {
|
||||
store.dispatchWithMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card))
|
||||
store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success)
|
||||
store.onUserWalletSelected(userWallet = userWallet)
|
||||
|
||||
afterScanIntent?.let {
|
||||
WalletConnectLinkIntentHandler().handleIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun disableUserWalletsSaving() {
|
||||
userWalletsListManager.clear()
|
||||
.flatMap { walletStoresManager.clear() }
|
||||
.flatMap { tangemSdkManager.clearSavedUserCodes() }
|
||||
|
|
@ -60,48 +141,6 @@ internal class WelcomeMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithBiometrics(state: WelcomeState) = scope.launch {
|
||||
userWalletsListManager.unlockIfLockable()
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to unlock user wallets with biometrics")
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Error(error))
|
||||
}
|
||||
.doOnSuccess { selectedUserWallet ->
|
||||
store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Biometric))
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Success)
|
||||
store.onUserWalletSelected(userWallet = selectedUserWallet)
|
||||
|
||||
state.intent?.let {
|
||||
WalletConnectLinkIntentHandler().handleIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCard(state: WelcomeState, lifecycleCoroutineScope: LifecycleCoroutineScope) {
|
||||
lifecycleCoroutineScope.launch {
|
||||
scanCardInternal { scanResponse ->
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal
|
||||
|
||||
userWalletsListManager.save(userWallet, canOverride = true)
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to save user wallet")
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(error))
|
||||
}
|
||||
.doOnSuccess {
|
||||
store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card))
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
|
||||
store.onUserWalletSelected(userWallet = userWallet)
|
||||
|
||||
state.intent?.let {
|
||||
WalletConnectLinkIntentHandler().handleIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend inline fun scanCardInternal(crossinline onCardScanned: suspend (ScanResponse) -> Unit) {
|
||||
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = preferencesStorage.shouldSaveAccessCodes,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ internal object WelcomeReducer {
|
|||
|
||||
private fun internalReduce(action: WelcomeAction, state: WelcomeState): WelcomeState {
|
||||
return when (action) {
|
||||
is WelcomeAction.SetInitialIntent -> state.copy(intent = action.intent)
|
||||
is WelcomeAction.SetCoroutineScope -> state.copy(scope = action.scope)
|
||||
is WelcomeAction.ClearCoroutineScope -> state.copy(scope = null)
|
||||
is WelcomeAction.ProceedWithIntent -> state.copy(intent = action.intent)
|
||||
is WelcomeAction.ProceedWithBiometrics -> state.copy(isUnlockWithBiometricsInProgress = true)
|
||||
is WelcomeAction.ProceedWithCard -> state.copy(isUnlockWithCardInProgress = true)
|
||||
is WelcomeAction.ProceedWithBiometrics.Error -> state.copy(
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ package com.tangem.tap.features.welcome.redux
|
|||
|
||||
import android.content.Intent
|
||||
import com.tangem.common.core.TangemError
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class WelcomeState(
|
||||
val scope: CoroutineScope? = null,
|
||||
val isUnlockWithBiometricsInProgress: Boolean = false,
|
||||
val isUnlockWithCardInProgress: Boolean = false,
|
||||
val intent: Intent? = null,
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import androidx.compose.material.SnackbarHostState
|
|||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.ui.components.SystemBarsEffect
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -33,8 +33,6 @@ internal class WelcomeFragment : ComposeFragment() {
|
|||
@Inject
|
||||
override lateinit var appThemeModeHolder: AppThemeModeHolder
|
||||
|
||||
private val viewModel by viewModels<WelcomeViewModel>()
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
Analytics.eraseContext()
|
||||
|
|
@ -43,6 +41,9 @@ internal class WelcomeFragment : ComposeFragment() {
|
|||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
val viewModel = hiltViewModel<WelcomeViewModel>()
|
||||
LocalLifecycleOwner.current.lifecycle.addObserver(viewModel)
|
||||
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference())
|
||||
|
|
@ -66,7 +67,7 @@ internal class WelcomeFragment : ComposeFragment() {
|
|||
showUnlockProgress = state.showUnlockWithBiometricsProgress,
|
||||
showScanCardProgress = state.showUnlockWithCardProgress,
|
||||
onUnlockClick = viewModel::unlockWallets,
|
||||
onScanCardClick = { viewModel.scanCard(lifecycleCoroutineScope = lifecycleScope) },
|
||||
onScanCardClick = viewModel::scanCard,
|
||||
)
|
||||
|
||||
SnackbarHost(
|
||||
|
|
@ -87,4 +88,8 @@ internal class WelcomeFragment : ComposeFragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val INITIAL_INTENT_KEY = "intent"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.welcome.ui
|
||||
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.ViewModel
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.*
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
|
|
@ -12,28 +12,50 @@ import com.tangem.tap.features.welcome.redux.WelcomeAction
|
|||
import com.tangem.tap.features.welcome.redux.WelcomeState
|
||||
import com.tangem.tap.features.welcome.ui.model.WarningModel
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
internal class WelcomeViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(),
|
||||
StoreSubscriber<WelcomeState>,
|
||||
DefaultLifecycleObserver {
|
||||
|
||||
private val initialIntent: Intent? = savedStateHandle[WelcomeFragment.INITIAL_INTENT_KEY]
|
||||
|
||||
internal class WelcomeViewModel : ViewModel(), StoreSubscriber<WelcomeState> {
|
||||
private val stateInternal = MutableStateFlow(WelcomeScreenState())
|
||||
val state: StateFlow<WelcomeScreenState> = stateInternal
|
||||
|
||||
init {
|
||||
store.dispatch(WelcomeAction.SetCoroutineScope(viewModelScope))
|
||||
|
||||
subscribeToStoreChanges()
|
||||
initGlobalState()
|
||||
}
|
||||
|
||||
fun unlockWallets() {
|
||||
Analytics.send(SignIn.ButtonBiometricSignIn())
|
||||
store.dispatch(WelcomeAction.ProceedWithBiometrics)
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
val welcomeAction = if (initialIntent != null) {
|
||||
WelcomeAction.ProceedWithIntent(initialIntent)
|
||||
} else {
|
||||
WelcomeAction.ProceedWithBiometrics()
|
||||
}
|
||||
|
||||
store.dispatch(welcomeAction)
|
||||
}
|
||||
|
||||
fun scanCard(lifecycleCoroutineScope: LifecycleCoroutineScope) {
|
||||
fun unlockWallets() {
|
||||
Analytics.send(SignIn.ButtonBiometricSignIn())
|
||||
store.dispatch(WelcomeAction.ProceedWithBiometrics())
|
||||
}
|
||||
|
||||
fun scanCard() {
|
||||
Analytics.send(SignIn.ButtonCardSignIn())
|
||||
store.dispatch(WelcomeAction.ProceedWithCard(lifecycleCoroutineScope))
|
||||
store.dispatch(WelcomeAction.ProceedWithCard)
|
||||
}
|
||||
|
||||
fun closeError() {
|
||||
|
|
@ -60,6 +82,7 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber<WelcomeState> {
|
|||
}
|
||||
|
||||
override fun onCleared() {
|
||||
store.dispatch(WelcomeAction.ClearCoroutineScope)
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ okHttp-prettyLogging = "3.1.0"
|
|||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-354"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-300"
|
||||
tangemCardSdk = "develop-302"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds
|
||||
# endregion Tangem
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue