Updated on 2026-08-14

This commit is contained in:
Tangem 2021-09-25 01:51:33 +03:00
parent ed8aa753ce
commit 63eaedff8a
21 changed files with 130 additions and 140 deletions

View file

@ -2,9 +2,13 @@ package com.tangem.tap.common
import android.app.Dialog
import android.content.Context
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.global.GlobalState
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.*
import com.tangem.tap.features.onboarding.products.note.OnboardingAddressInfoDialog
import com.tangem.tap.features.onboarding.redux.OnboardingAction
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
import com.tangem.tap.store
import com.tangem.wallet.R
import org.rekotlin.StoreSubscriber
@ -37,35 +41,40 @@ class DialogManager : StoreSubscriber<GlobalState> {
val context = context ?: return
if (dialog != null) return
when (state.dialog) {
dialog = when (state.dialog) {
is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context)
is WalletConnectDialog.UnsupportedCard ->
dialog = SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_scanner_error_no_ethereum_wallet,
context = context
SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_scanner_error_no_ethereum_wallet,
context = context
)
is WalletConnectDialog.OpeningSessionRejected -> {
dialog = SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_same_wcuri,
context = context
SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_same_wcuri,
context = context
)
}
is WalletConnectDialog.SessionTimeout -> {
dialog = SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_error_timeout,
context = context
SimpleAlertDialog.create(
titleRes = R.string.wallet_connect,
messageRes = R.string.wallet_connect_error_timeout,
context = context
)
}
is WalletConnectDialog.ApproveWcSession ->
dialog = ApproveWcSessionDialog.create(state.dialog.session, context)
ApproveWcSessionDialog.create(state.dialog.session, context)
is WalletConnectDialog.ClipboardOrScanQr ->
dialog = ClipboardOrScanQrDialog.create(state.dialog.clipboardUri, context)
ClipboardOrScanQrDialog.create(state.dialog.clipboardUri, context)
is WalletConnectDialog.RequestTransaction ->
dialog = TransactionDialog.create(state.dialog.dialogData, context)
TransactionDialog.create(state.dialog.dialogData, context)
is WalletConnectDialog.PersonalSign ->
dialog = PersonalSignDialog.create(state.dialog.data, context)
PersonalSignDialog.create(state.dialog.data, context)
is OnboardingAction.Dialog.AddressInfo -> {
OnboardingAddressInfoDialog(state.dialog, context)
}
else -> null
}
dialog?.show()
}

View file

@ -1,6 +1,8 @@
package com.tangem.tap.common.extensions
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.scope
import com.tangem.tap.store
import kotlinx.coroutines.Dispatchers
@ -8,8 +10,36 @@ import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.Store
fun Store<AppState>.dispatchOnMain(action: Action) {
fun Store<*>.dispatchOnMain(action: Action) {
scope.launch(Dispatchers.Main) {
store.dispatch(action)
}
}
}
fun Store<*>.dispatchOpenUrl(url: String) {
store.dispatch(NavigationAction.OpenUrl(url))
}
fun Store<*>.dispatchNotification(resId: Int) {
scope.launch(Dispatchers.Main) {
store.dispatch(GlobalAction.ShowNotification(resId))
}
}
fun Store<*>.dispatchToastNotification(resId: Int) {
scope.launch(Dispatchers.Main) {
store.dispatch(GlobalAction.ShowToastNotification(resId))
}
}
fun Store<*>.dispatchDialogShow(dialog: StateDialog) {
scope.launch(Dispatchers.Main) {
store.dispatch(GlobalAction.ShowDialog(dialog))
}
}
fun Store<*>.dispatchDialogHide() {
scope.launch(Dispatchers.Main) {
store.dispatch(GlobalAction.HideDialog)
}
}

View file

@ -0,0 +1,10 @@
package com.tangem.tap.common.redux
/**
[REDACTED_AUTHOR]
*/
interface StateDialog
sealed class AppDialog : StateDialog {
object ScanFailsDialog : AppDialog()
}

View file

@ -4,6 +4,9 @@ import com.tangem.blockchain.common.WalletManager
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemError
import com.tangem.tap.common.redux.DebugErrorAction
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.ToastNotificationAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
@ -17,6 +20,14 @@ import org.rekotlin.Action
sealed class GlobalAction : Action {
// notifications
data class ShowNotification(override val messageResource: Int) : GlobalAction(), NotificationAction
data class ShowToastNotification(override val messageResource: Int) : GlobalAction(), ToastNotificationAction
// dialogs
data class ShowDialog(val stateDialog: StateDialog) : GlobalAction()
object HideDialog : GlobalAction()
data class DebugShowError(override val error: TapError) : GlobalAction(), DebugErrorAction
data class ReadCard(
@ -56,9 +67,6 @@ sealed class GlobalAction : Action {
data class SendFeedback(val emailData: EmailData) : GlobalAction()
data class UpdateFeedbackInfo(val walletManagers: List<WalletManager>) : GlobalAction()
data class ShowDialog(val stateDialog: StateDialog) : GlobalAction()
object HideDialog : GlobalAction()
object GetMoonPayUserStatus : GlobalAction() {
data class Success(val moonPayUserStatus: MoonPayUserStatus) : GlobalAction()
}

View file

@ -4,10 +4,11 @@ import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.common.services.Result
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.home.redux.HomeAction
import com.tangem.tap.features.send.redux.SendAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.moonpay.MoonpayService
@ -37,8 +38,7 @@ private val globalMiddlewareHandler: Middleware<AppState> = { dispatch, appState
if (action.result.error is TangemSdkError.UserCancelled) {
store.dispatch(GlobalAction.ScanFailsCounter.Increment)
if (store.state.globalState.scanCardFailsCounter >= 2) {
store.dispatch(HomeAction.ShowDialog.ScanFails)
store.dispatch(WalletAction.ShowDialog.ScanFails)
store.dispatchDialogShow(AppDialog.ScanFailsDialog)
}
} else {
store.dispatch(GlobalAction.ScanFailsCounter.Reset)

View file

@ -1,6 +1,7 @@
package com.tangem.tap.common.redux.global
import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.domain.PayIdManager
import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.domain.configurable.config.ConfigManager
@ -27,7 +28,4 @@ data class GlobalState(
) : StateType
typealias CryptoCurrencyName = String
typealias FiatCurrencyName = String
interface StateDialog
typealias FiatCurrencyName = String

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.details.redux.walletconnect
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.WalletManager
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData
import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionRequestDialogData
import com.trustwallet.walletconnect.models.WCPeerMeta

View file

@ -1,15 +1,9 @@
package com.tangem.tap.features.home
import android.app.Dialog
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.tangem.tap.common.extensions.safeStartActivity
import com.tangem.tap.common.extensions.toast
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import com.tangem.tap.common.redux.navigation.ShareElement
import com.tangem.tap.common.toggleWidget.IndeterminateProgressButtonWidget
@ -17,9 +11,7 @@ import com.tangem.tap.common.toggleWidget.ViewStateWidget
import com.tangem.tap.common.transitions.FrontCardEnterTransition
import com.tangem.tap.common.transitions.FrontCardExitTransition
import com.tangem.tap.features.home.redux.HomeAction
import com.tangem.tap.features.home.redux.HomeDialog
import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fragment_home.*
@ -28,9 +20,7 @@ import java.lang.ref.WeakReference
class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState> {
lateinit var btnScanCard: ViewStateWidget
private var dialog: Dialog? = null
private lateinit var btnScanCard: ViewStateWidget
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -74,36 +64,10 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
override fun newState(state: HomeState) {
if (activity == null) return
handleOpenUrl(state)
handleDialog(state.dialog)
btnScanCard.changeState(state.btnScanState.progressState)
btnScanCard.mainView.isEnabled = state.btnScanState.enabled
}
private fun handleOpenUrl(state: HomeState) {
if (state.openUrl == null) return
val context = context ?: return
val uri = Uri.parse(state.openUrl)
val intent = Intent(Intent.ACTION_VIEW, uri)
context.safeStartActivity(intent, null, { toast(it.toString()) }, {
store.dispatch(HomeAction.SetOpenUrl(null))
})
}
private fun handleDialog(stateDialog: StateDialog?) {
when (stateDialog) {
is HomeDialog.ScanFailsDialog -> {
if (dialog == null) dialog = ScanFailsDialog.create(requireContext()).apply { show() }
}
else -> {
dialog?.dismiss()
dialog = null
}
}
}
override fun onDestroyView() {
store.dispatch(HomeAction.SetFragmentShareTransition(null))
super.onDestroyView()

View file

@ -5,18 +5,14 @@ import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import org.rekotlin.Action
sealed class HomeAction : Action {
object Init : HomeAction()
data class SetFragmentShareTransition(val shareTransition: FragmentShareTransition?) : HomeAction()
// from ui
object ReadCard : HomeAction()
object GoToShop : HomeAction()
class SetOpenUrl(val url: String?) : HomeAction()
class SetTermsOfUseState(val isDisclaimerAccepted: Boolean) : HomeAction()
// internal
object Init : HomeAction()
data class SetFragmentShareTransition(val shareTransition: FragmentShareTransition?) : HomeAction()
data class SetTermsOfUseState(val isDisclaimerAccepted: Boolean) : HomeAction()
data class ChangeScanCardButtonState(val state: IndeterminateProgressButton) : HomeAction()
object ShowDialog : HomeAction() {
object ScanFails : HomeAction()
}
object HideDialog : HomeAction()
}

View file

@ -1,6 +1,7 @@
package com.tangem.tap.features.home.redux
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
@ -38,7 +39,7 @@ private val homeMiddleware: Middleware<AppState> = { dispatch, state ->
launchOnboardingService()
}
}
is HomeAction.GoToShop -> store.dispatch(HomeAction.SetOpenUrl(HomeMiddleware.CARD_SHOP_URI))
is HomeAction.GoToShop -> store.dispatchOpenUrl(HomeMiddleware.CARD_SHOP_URI)
}
next(action)
}

View file

@ -21,18 +21,9 @@ private fun internalReduce(action: Action, state: AppState): HomeState {
is HomeAction.SetTermsOfUseState -> {
state = state.copy(isDisclaimerAccepted = action.isDisclaimerAccepted)
}
is HomeAction.SetOpenUrl -> {
state = state.copy(openUrl = action.url)
}
is HomeAction.ChangeScanCardButtonState -> {
state = state.copy(btnScanState = action.state)
}
is HomeAction.ShowDialog.ScanFails -> {
state = state.copy(dialog = HomeDialog.ScanFailsDialog)
}
is HomeAction.HideDialog -> {
state = state.copy(dialog = null)
}
}
return state

View file

@ -1,19 +1,12 @@
package com.tangem.tap.features.home.redux
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import com.tangem.tap.features.send.redux.states.ButtonState
import org.rekotlin.StateType
data class HomeState(
val openUrl: String? = null,
val isDisclaimerAccepted: Boolean = false,
val shareTransition: FragmentShareTransition? = null,
val btnScanState: IndeterminateProgressButton = IndeterminateProgressButton(ButtonState.ENABLED),
val dialog: StateDialog? = null,
) : StateType
sealed class HomeDialog : StateDialog {
object ScanFailsDialog : HomeDialog()
}
val isDisclaimerAccepted: Boolean = false,
val shareTransition: FragmentShareTransition? = null,
val btnScanState: IndeterminateProgressButton = IndeterminateProgressButton(ButtonState.ENABLED),
) : StateType

View file

@ -5,13 +5,13 @@ import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.WalletManager
import com.tangem.tap.common.redux.ErrorAction
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.ToastNotificationAction
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.tap.features.send.redux.states.FeeType
import com.tangem.tap.features.send.redux.states.MainCurrencyType
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.wallet.R
import org.rekotlin.Action
import java.math.BigDecimal

View file

@ -7,7 +7,7 @@ import com.tangem.common.extensions.isZero
import com.tangem.tap.common.CurrencyConverter
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.entities.TapCurrency
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.text.DecimalDigitsInputFilter
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage

View file

@ -122,7 +122,6 @@ sealed class WalletAction : Action {
object ShowDialog : WalletAction() {
object QrCode : WalletAction()
object ScanFails : WalletAction()
object SignedHashesMultiWalletDialog : WalletAction()
object ChooseTradeActionDialog : WalletAction()
}

View file

@ -5,8 +5,9 @@ import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.address.AddressType
import com.tangem.blockchain.extensions.isAboveZero
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.extensions.toQrCode
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.extensions.toSendableAmounts
import com.tangem.tap.domain.topup.TradeCryptoHelper
@ -141,7 +142,6 @@ sealed class WalletDialog: StateDialog {
) : WalletDialog()
data class SelectAmountToSendDialog(val amounts: List<Amount>?) : WalletDialog()
object ScanFailsDialog : WalletDialog()
object SignedHashesMultiWalletDialog : WalletDialog()
object ChooseTradeActionDialog : WalletDialog()
}
@ -165,8 +165,9 @@ data class AddressData(
val type: AddressType,
val shareUrl: String,
val exploreUrl: String,
val qrCode: Bitmap? = null
)
) {
val qrCode: Bitmap by lazy { shareUrl.toQrCode() }
}
data class Artwork(
val artworkId: String,

View file

@ -232,9 +232,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
)
)
}
is WalletAction.ShowDialog.ScanFails -> {
newState = newState.copy(walletDialog = WalletDialog.ScanFailsDialog)
}
is WalletAction.ShowDialog.SignedHashesMultiWalletDialog -> {
newState = newState.copy(walletDialog = WalletDialog.SignedHashesMultiWalletDialog)
}
@ -276,30 +273,34 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
fun createAddressList(wallet: Wallet?, walletAddresses: WalletAddresses? = null): WalletAddresses? {
if (wallet == null) return null
val listOfAddressData = wallet.createAddressesData()
// restore a selected wallet address
var indexOfSelectedWallet = 0
walletAddresses?.let {
val index =
listOfAddressData.indexOfFirst { it.address == walletAddresses.selectedAddress.address }
if (index != -1) indexOfSelectedWallet = index
}
return WalletAddresses(listOfAddressData[indexOfSelectedWallet], listOfAddressData)
}
fun Wallet.createAddressesData(): List<AddressData> {
val listOfAddressData = mutableListOf<AddressData>()
// put a defaultAddress at the first place
wallet.addresses.forEach {
addresses.forEach {
val addressData = AddressData(
it.value,
it.type,
wallet.getShareUri(it.value),
wallet.getExploreUrl(it.value)
it.value,
it.type,
getShareUri(it.value),
getExploreUrl(it.value)
)
if (it.type == wallet.blockchain.defaultAddressType()) {
if (it.type == blockchain.defaultAddressType()) {
listOfAddressData.add(0, addressData)
} else {
listOfAddressData.add(addressData)
}
}
// restore a selected wallet address
var indexOfSelectedWallet = 0
walletAddresses?.let {
val index =
listOfAddressData.indexOfFirst { it.address == walletAddresses.selectedAddress.address }
if (index != -1) indexOfSelectedWallet = index
}
return WalletAddresses(listOfAddressData[indexOfSelectedWallet], listOfAddressData)
return listOfAddressData
}
private fun handleCheckSignedHashesActions(

View file

@ -12,7 +12,7 @@ import androidx.transition.TransitionInflater
import com.squareup.picasso.Picasso
import com.tangem.tap.common.SnackbarHandler
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.wallet.models.PendingTransaction
import com.tangem.tap.features.wallet.redux.*

View file

@ -2,10 +2,9 @@ package com.tangem.tap.features.wallet.ui.dialogs
import android.content.Context
import androidx.appcompat.app.AlertDialog
import com.tangem.tap.common.extensions.dispatchDialogHide
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.feedback.ScanFailsEmail
import com.tangem.tap.features.home.redux.HomeAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.wallet.R
@ -23,10 +22,7 @@ class ScanFailsDialog {
store.dispatch(GlobalAction.SendFeedback(ScanFailsEmail()))
}
setNegativeButton(R.string.common_cancel) { _, _ -> }
setOnDismissListener {
store.dispatch(HomeAction.HideDialog)
store.dispatch(WalletAction.HideDialog)
}
setOnDismissListener { store.dispatchDialogHide() }
}.create()
}
}

View file

@ -4,7 +4,7 @@ import android.app.Dialog
import androidx.recyclerview.widget.LinearLayoutManager
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.tokens.redux.TokensAction
@ -14,7 +14,6 @@ import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.ui.BalanceStatus
import com.tangem.tap.features.wallet.ui.WalletFragment
import com.tangem.tap.features.wallet.ui.adapters.WalletAdapter
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
import com.tangem.tap.features.wallet.ui.dialogs.SignedHashesWarningDialog
import com.tangem.tap.store
import com.tangem.wallet.R
@ -134,9 +133,6 @@ class MultiWalletView : WalletView {
val fragment = fragment ?: return
val context = fragment.context ?: return
when (walletDialog) {
is WalletDialog.ScanFailsDialog -> {
if (dialog == null) dialog = ScanFailsDialog.create(context).apply { show() }
}
is WalletDialog.SignedHashesMultiWalletDialog -> {
if (dialog == null) {
dialog = SignedHashesWarningDialog.create(context).apply { show() }

View file

@ -6,7 +6,7 @@ import android.view.ViewGroup
import android.widget.Button
import androidx.recyclerview.widget.LinearLayoutManager
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.global.StateDialog
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.twins.TwinCardNumber
@ -248,9 +248,6 @@ class SingleWalletView : WalletView {
this.show(walletDialog.amounts)
}
}
is WalletDialog.ScanFailsDialog -> {
if (dialog == null) dialog = ScanFailsDialog.create(context).apply { show() }
}
is WalletDialog.SignedHashesMultiWalletDialog -> {
if (dialog == null) {
dialog = SignedHashesWarningDialog.create(context).apply { show() }