Updated on 2026-08-14

This commit is contained in:
Tangem 2022-11-28 18:08:46 +03:00
parent 0d993b5141
commit e72bf276da
18 changed files with 568 additions and 21 deletions

View file

@ -0,0 +1,90 @@
package com.tangem.tap.features.welcome.redux
import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.domain.scanCard.ScanCardProcessor
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
internal class WelcomeMiddleware {
val middleware: Middleware<AppState> = { _, _ ->
{ next ->
{ action ->
if (action is WelcomeAction) {
handleAction(action)
}
next(action)
}
}
}
private fun handleAction(action: WelcomeAction) {
when (action) {
is WelcomeAction.ProceedWithBiometrics -> proceedWithBiometry()
is WelcomeAction.ProceedWithCard -> proceedWithCard()
is WelcomeAction.ProceedWithBiometrics.Error -> Unit
is WelcomeAction.ProceedWithCard.Error -> Unit
is WelcomeAction.ProceedWithBiometrics.Success -> Unit
is WelcomeAction.ProceedWithCard.Success -> Unit
is WelcomeAction.CloseError -> Unit
}
}
private fun proceedWithBiometry() {
scope.launch {
userWalletsListManager.unlockWithBiometry()
.doOnFailure { error ->
store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Error(error))
}
.doOnSuccess { selectedUserWallet ->
if (selectedUserWallet != null) {
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Success)
store.onUserWalletSelected(selectedUserWallet)
}
}
}
}
private fun proceedWithCard() = scope.launch {
scanCardInternal { scanResponse ->
val userWallet = UserWallet(scanResponse)
userWalletsListManager.unlockWithCard(userWallet)
.doOnFailure { error ->
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(error))
}
.doOnSuccess {
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
store.onUserWalletSelected(userWallet)
}
}
}
private suspend inline fun scanCardInternal(
crossinline onCardScanned: suspend (ScanResponse) -> Unit,
) {
ScanCardProcessor.scan(
onSuccess = { scanResponse ->
scope.launch { onCardScanned(scanResponse) }
},
onFailure = {
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Error(it))
},
onWalletNotCreated = {
store.dispatchOnMain(WelcomeAction.ProceedWithCard.Success)
},
)
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.tap.features.welcome.redux
import com.tangem.tap.common.redux.AppState
import org.rekotlin.Action
internal object WelcomeReducer {
fun reduce(action: Action, state: AppState): WelcomeState {
return if (action is WelcomeAction) {
internalReduce(action, state.welcomeState)
} else state.welcomeState
}
private fun internalReduce(action: WelcomeAction, state: WelcomeState): WelcomeState {
return when (action) {
is WelcomeAction.ProceedWithBiometrics -> state.copy(isUnlockWithBiometricsInProgress = true)
is WelcomeAction.ProceedWithCard -> state.copy(isUnlockWithCardInProgress = true)
is WelcomeAction.ProceedWithBiometrics.Error -> state.copy(
error = action.error,
isUnlockWithBiometricsInProgress = false,
)
is WelcomeAction.ProceedWithCard.Error -> state.copy(
error = action.error,
isUnlockWithCardInProgress = false,
)
is WelcomeAction.ProceedWithBiometrics.Success -> state.copy(isUnlockWithBiometricsInProgress = false)
is WelcomeAction.ProceedWithCard.Success -> state.copy(isUnlockWithCardInProgress = false)
is WelcomeAction.CloseError -> state.copy(error = null)
}
}
}

View file

@ -1,5 +1,10 @@
package com.tangem.tap.features.welcome.redux
import com.tangem.common.core.TangemError
import org.rekotlin.StateType
class WelcomeState : StateType
data class WelcomeState(
val isUnlockWithBiometricsInProgress: Boolean = false,
val isUnlockWithCardInProgress: Boolean = false,
val error: TangemError? = null,
) : StateType

View file

@ -20,6 +20,7 @@ import androidx.fragment.app.viewModels
import com.tangem.core.ui.components.SystemBarsEffect
import com.tangem.core.ui.fragments.ComposeFragment
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
import com.tangem.tap.features.welcome.ui.components.WelcomeScreenContent
import com.tangem.wallet.R
@ -37,7 +38,7 @@ internal class WelcomeFragment : ComposeFragment<WelcomeScreenState>() {
state: WelcomeScreenState,
) {
val snackbarHostState = remember { SnackbarHostState() }
val errorMessage by rememberUpdatedState(newValue = state.error?.customMessage)
val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference())
val backgroundColor = colorResource(id = R.color.background_primary)
SystemBarsEffect {

View file

@ -1,11 +1,11 @@
package com.tangem.tap.features.welcome.ui
import androidx.compose.runtime.Immutable
import com.tangem.common.core.TangemError
import com.tangem.tap.features.details.ui.cardsettings.TextReference
@Immutable
internal data class WelcomeScreenState(
val showUnlockWithBiometricsProgress: Boolean = false,
val showUnlockWithCardProgress: Boolean = false,
val error: TangemError? = null,
val error: TextReference? = null,
)

View file

@ -1,6 +1,8 @@
package com.tangem.tap.features.welcome.ui
import androidx.lifecycle.ViewModel
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.welcome.redux.WelcomeAction
import com.tangem.tap.features.welcome.redux.WelcomeState
import com.tangem.tap.store
@ -15,6 +17,7 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber<WelcomeState> {
init {
subscribeToStoreChanges()
initGlobalState()
}
fun unlockWallets() {
@ -31,8 +34,16 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber<WelcomeState> {
override fun newState(state: WelcomeState) {
stateInternal.update { prevState ->
// TODO: Update screen state
prevState
prevState.copy(
showUnlockWithBiometricsProgress = state.isUnlockWithBiometricsInProgress,
showUnlockWithCardProgress = state.isUnlockWithCardInProgress,
error = state.error
?.takeUnless { it.silent }
?.let { error ->
error.messageResId?.let { TextReference.Res(it) }
?: TextReference.Str(error.customMessage)
},
)
}
}
@ -46,4 +57,10 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber<WelcomeState> {
.select { it.welcomeState }
}
}
private fun initGlobalState() {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.dispatch(GlobalAction.ExchangeManager.Init)
store.dispatch(GlobalAction.FetchUserCountry)
}
}