Updated on 2026-08-14
This commit is contained in:
parent
60ba581540
commit
88f7205293
15 changed files with 1 additions and 361 deletions
|
|
@ -54,7 +54,6 @@ import com.tangem.operations.backup.BackupService
|
|||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.tap.common.ActivityResultCallbackHolder
|
||||
import com.tangem.tap.common.DialogManager
|
||||
import com.tangem.tap.common.OnActivityResultCallback
|
||||
import com.tangem.tap.common.analytics.events.Push
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
|
|
@ -171,8 +170,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode>
|
||||
|
||||
private val dialogManager = DialogManager()
|
||||
|
||||
private val onActivityResultCallbacks = mutableListOf<OnActivityResultCallback>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -324,11 +321,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
override fun onStart() {
|
||||
super.onStart()
|
||||
TangemLogger.i("onStart")
|
||||
dialogManager.onStart(this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
dialogManager.onStop()
|
||||
super.onStop()
|
||||
TangemLogger.i("onStop")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
package com.tangem.tap.common
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.ui.ScanFailsDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.WalletActivationErrorDialog
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class DialogManager : StoreSubscriber<GlobalState> {
|
||||
var context: Context? = null
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
fun onStart(context: Context) {
|
||||
this.context = context
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.globalState == newState.globalState
|
||||
}.select { it.globalState }
|
||||
}
|
||||
}
|
||||
|
||||
fun onStop() {
|
||||
this.context = null
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
override fun newState(state: GlobalState) {
|
||||
if (state.dialog == null) {
|
||||
dialog?.dismiss()
|
||||
dialog = null
|
||||
return
|
||||
}
|
||||
val context = context ?: return
|
||||
if (dialog != null) return
|
||||
|
||||
dialog = when (state.dialog) {
|
||||
is StateDialog.ScanFailsDialog -> ScanFailsDialog.create(
|
||||
context = context,
|
||||
source = state.dialog.source,
|
||||
onTryAgain = state.dialog.onTryAgain,
|
||||
)
|
||||
is OnboardingDialog.WalletActivationError -> WalletActivationErrorDialog.create(context, state.dialog)
|
||||
else -> null
|
||||
}
|
||||
dialog?.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,9 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -45,26 +40,6 @@ suspend fun Store<AppState>.onUserWalletSelected(userWallet: UserWallet) {
|
|||
state.globalState.tapWalletManager.onWalletSelected(userWallet)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fatal used to indicate errors that should not normally occur
|
||||
*/
|
||||
fun Store<AppState>.dispatchDebugErrorNotification(message: String, fatal: Boolean = false) {
|
||||
val prefix = if (fatal) "FATAL ERROR: " else "DEBUG ERROR: "
|
||||
dispatchDebugErrorNotification(TapError.CustomError("$prefix $message"))
|
||||
}
|
||||
|
||||
fun Store<AppState>.dispatchDebugErrorNotification(error: TapError) {
|
||||
inject(DaggerGraphState::uiMessageSender).send(SnackbarMessage(stringReference(error.message ?: "debug error")))
|
||||
}
|
||||
|
||||
fun Store<*>.dispatchDialogShow(dialog: StateDialog) {
|
||||
dispatchOnMain(GlobalAction.ShowDialog(dialog))
|
||||
}
|
||||
|
||||
fun Store<*>.dispatchDialogHide() {
|
||||
dispatchOnMain(GlobalAction.HideDialog)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch action inside a coroutine with the Main dispatcher
|
||||
*/
|
||||
|
|
@ -76,14 +51,6 @@ suspend fun dispatchOnMain(vararg actions: Action) {
|
|||
withMainContext { actions.forEach { store.dispatch(it) } }
|
||||
}
|
||||
|
||||
fun Store<AppState>.dispatchOpenUrl(url: String) {
|
||||
inject(DaggerGraphState::urlOpener).openUrl(url)
|
||||
}
|
||||
|
||||
fun Store<AppState>.dispatchShare(url: String) {
|
||||
inject(DaggerGraphState::shareManager).shareText(url)
|
||||
}
|
||||
|
||||
fun Store<AppState>.dispatchNavigationAction(action: AppRouter.() -> Unit) {
|
||||
inject(DaggerGraphState::appRouter).action()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,10 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class GlobalAction : Action {
|
||||
|
||||
// dialogs
|
||||
data class ShowDialog(val stateDialog: StateDialog) : GlobalAction()
|
||||
object HideDialog : GlobalAction()
|
||||
|
||||
object ScanFailsCounter {
|
||||
data class ChooseBehavior(
|
||||
val result: CompletionResult<ScanResponse>,
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
globalState.copy(appCurrency = action.appCurrency)
|
||||
}
|
||||
is GlobalAction.IsSignWithRing -> globalState.copy(isLastSignWithRing = action.isSignWithRing)
|
||||
is GlobalAction.ShowDialog -> {
|
||||
globalState.copy(dialog = action.stateDialog)
|
||||
}
|
||||
is GlobalAction.HideDialog -> {
|
||||
globalState.copy(dialog = null)
|
||||
}
|
||||
else -> globalState
|
||||
}
|
||||
}
|
||||
|
|
@ -2,24 +2,16 @@ package com.tangem.tap.common.redux.global
|
|||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.tap.domain.TapWalletManager
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class GlobalState(
|
||||
@Deprecated("Use scan response from selected user wallet")
|
||||
val scanResponse: ScanResponse? = null,
|
||||
val onboardingState: OnboardingState = OnboardingState(),
|
||||
val tapWalletManager: TapWalletManager = TapWalletManager(),
|
||||
val appCurrency: AppCurrency = AppCurrency.Default,
|
||||
val scanCardFailsCounter: Int = 0,
|
||||
val dialog: StateDialog? = null,
|
||||
val isLastSignWithRing: Boolean = false,
|
||||
) : StateType
|
||||
|
||||
typealias CryptoCurrencyName = String
|
||||
|
||||
data class OnboardingState(
|
||||
val isOnboardingStarted: Boolean = false,
|
||||
val shouldResetOnCreate: Boolean = false,
|
||||
)
|
||||
typealias CryptoCurrencyName = String
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
package com.tangem.tap.common.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.core.view.isVisible
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
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.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object ScanFailsDialog {
|
||||
|
||||
private const val HOW_TO_SCAN_RU_LINK = "https://tangem.com/ru/blog/post/scan-tangem-card/"
|
||||
private const val HOW_TO_SCAN_LINK = "https://tangem.com/en/blog/post/scan-tangem-card/"
|
||||
private const val RUSSIA_LOCALE = "ru"
|
||||
|
||||
fun create(context: Context, source: StateDialog.ScanFailsSource, onTryAgain: (() -> Unit)? = null): AlertDialog {
|
||||
return AlertDialog.Builder(context, R.style.CustomMaterialDialog).apply {
|
||||
val customView = View.inflate(context, R.layout.dialog_scan_fails, null)
|
||||
val sourceAnalytics = when (source) {
|
||||
StateDialog.ScanFailsSource.MAIN -> AnalyticsParam.ScreensSources.Main
|
||||
StateDialog.ScanFailsSource.SIGN_IN -> AnalyticsParam.ScreensSources.SignIn
|
||||
StateDialog.ScanFailsSource.SETTINGS -> AnalyticsParam.ScreensSources.Settings
|
||||
StateDialog.ScanFailsSource.INTRO -> AnalyticsParam.ScreensSources.Intro
|
||||
}
|
||||
val tryAgainBtn: TextView? = customView.findViewById(R.id.try_again_button)
|
||||
if (onTryAgain != null) {
|
||||
tryAgainBtn?.isVisible = true
|
||||
tryAgainBtn?.setOnClickListener {
|
||||
store.dispatchDialogHide()
|
||||
Analytics.send(
|
||||
ScanFailsDialogAnalytics(
|
||||
button = ScanFailsDialogAnalytics.Buttons.TRY_AGAIN,
|
||||
source = sourceAnalytics,
|
||||
),
|
||||
)
|
||||
onTryAgain()
|
||||
}
|
||||
} else {
|
||||
tryAgainBtn?.isVisible = false
|
||||
}
|
||||
customView.findViewById<TextView>(R.id.how_to_scan_button)?.setOnClickListener {
|
||||
Analytics.send(
|
||||
ScanFailsDialogAnalytics(
|
||||
button = ScanFailsDialogAnalytics.Buttons.HOW_TO_SCAN,
|
||||
source = sourceAnalytics,
|
||||
),
|
||||
)
|
||||
val locale = Locale.current.region
|
||||
val link = if (locale.lowercase() == RUSSIA_LOCALE) 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))
|
||||
|
||||
scope.launch {
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase)
|
||||
.invoke(type = FeedbackEmailType.ScanningProblem)
|
||||
}
|
||||
}
|
||||
customView.findViewById<TextView>(R.id.cancel_button)?.setOnClickListener {
|
||||
store.dispatchDialogHide()
|
||||
}
|
||||
setView(customView)
|
||||
setOnDismissListener { store.dispatchDialogHide() }
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.tap.features.onboarding
|
||||
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class OnboardingDialog : StateDialog {
|
||||
data class WalletActivationError(val onConfirm: () -> Unit) : OnboardingDialog()
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.tap.common.extensions.dispatchDialogHide
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object WalletActivationErrorDialog {
|
||||
|
||||
fun create(context: Context, dialog: OnboardingDialog.WalletActivationError): Dialog {
|
||||
return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply {
|
||||
setTitle(context.getString(R.string.onboarding_activation_error_title))
|
||||
setMessage(context.getString(R.string.onboarding_activation_error_message))
|
||||
setPositiveButton(R.string.common_ok) { _, _ -> dialog.onConfirm() }
|
||||
setNegativeButton(R.string.common_support) { _, _ ->
|
||||
// changed on email support [REDACTED_TASK_KEY]
|
||||
Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro))
|
||||
|
||||
val scanResponse = store.state.globalState.scanResponse
|
||||
?: error("ScanResponse must be not null")
|
||||
|
||||
val cardInfo = store.inject(DaggerGraphState::getWalletMetaInfoUseCase).invoke(scanResponse).getOrNull()
|
||||
?: error("CardInfo must be not null")
|
||||
|
||||
scope.launch {
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase)
|
||||
.invoke(type = FeedbackEmailType.DirectUserRequest(cardInfo))
|
||||
}
|
||||
}
|
||||
setOnDismissListener { store.dispatchDialogHide() }
|
||||
setCancelable(false)
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@ package com.tangem.tap.proxy
|
|||
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -32,8 +30,4 @@ class AppStateHolder @Inject constructor() : ReduxStateHolder {
|
|||
override suspend fun onUserWalletSelected(userWallet: UserWallet) {
|
||||
mainStore?.onUserWalletSelected(userWallet)
|
||||
}
|
||||
|
||||
override fun dispatchDialogShow(dialog: StateDialog) {
|
||||
mainStore?.dispatchDialogShow(dialog)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/background_primary"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="16dp"
|
||||
tools:layout_gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="38dp"
|
||||
android:text="@string/common_warning"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/text_primary_1"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="38dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/alert_troubleshooting_scan_card_title"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/try_again_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="38dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/alert_button_try_again"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/menu_accent_color"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/how_to_scan_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="38dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/alert_button_how_to_scan"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/menu_accent_color"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/request_support_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="38dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/alert_button_request_support"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/menu_accent_color"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cancel_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="38dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/common_cancel"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/warning_critical"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
|
@ -10,6 +10,4 @@ interface ReduxStateHolder {
|
|||
suspend fun dispatchWithMain(action: Action)
|
||||
|
||||
suspend fun onUserWalletSelected(userWallet: UserWallet)
|
||||
|
||||
fun dispatchDialogShow(dialog: StateDialog)
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.domain.redux
|
||||
|
||||
interface StateDialog {
|
||||
|
||||
data class ScanFailsDialog(val source: ScanFailsSource, val onTryAgain: (() -> Unit)? = null) : StateDialog
|
||||
|
||||
enum class ScanFailsSource {
|
||||
MAIN, SIGN_IN, SETTINGS, INTRO
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,6 @@ import com.tangem.domain.qrscanning.models.QrSendTarget
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
|
||||
|
|
@ -35,7 +33,6 @@ import javax.inject.Inject
|
|||
internal class DefaultWalletRouter @Inject constructor(
|
||||
private val router: AppRouter,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
) : InnerWalletRouter {
|
||||
|
||||
|
|
@ -117,10 +114,6 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
return router.stack.lastOrNull() is AppRoute.Wallet
|
||||
}
|
||||
|
||||
override fun openScanFailedDialog(onTryAgain: () -> Unit) {
|
||||
reduxStateHolder.dispatchDialogShow(StateDialog.ScanFailsDialog(StateDialog.ScanFailsSource.MAIN, onTryAgain))
|
||||
}
|
||||
|
||||
override fun openNFT(userWallet: UserWallet) {
|
||||
router.push(
|
||||
AppRoute.NFT(
|
||||
|
|
|
|||
|
|
@ -66,9 +66,6 @@ internal interface InnerWalletRouter {
|
|||
/** Is wallet last screen */
|
||||
fun isWalletLastScreen(): Boolean
|
||||
|
||||
/** Open scan failed dialog */
|
||||
fun openScanFailedDialog(onTryAgain: () -> Unit)
|
||||
|
||||
/** Open NFT collections screen */
|
||||
fun openNFT(userWallet: UserWallet)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue