Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-17 15:11:40 +05:00
parent f5b2046666
commit e8a2b10e6f
10 changed files with 170 additions and 19 deletions

View file

@ -46,7 +46,11 @@ class DialogManager : StoreSubscriber<GlobalState> {
dialog = when (state.dialog) {
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.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context)
is AppDialog.RussianCardholdersWarningDialog -> RussianCardholdersWarningBottomSheetDialog(

View file

@ -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"),
}
}

View file

@ -1,37 +1,76 @@
package com.tangem.tap.common.ui
import android.content.Context
import android.view.View
import android.widget.TextView
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.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
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.feedback.ScanFailsEmail
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.wallet.R
/**
[REDACTED_AUTHOR]
*/
object ScanFailsDialog {
fun create(context: Context, source: StateDialog.ScanFailsSource): AlertDialog {
return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply {
setTitle(context.getString(R.string.common_warning))
setMessage(R.string.alert_troubleshooting_scan_card_title)
setPositiveButton(R.string.alert_button_request_support) { _, _ ->
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
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/"
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 = 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(ScanFailsEmail()))
}
setNeutralButton(R.string.common_cancel) { _, _ -> }
customView.findViewById<TextView>(R.id.cancel_button)?.setOnClickListener {
store.dispatchDialogHide()
}
setView(customView)
setOnDismissListener { store.dispatchDialogHide() }
}.create()
}

View file

@ -0,0 +1,84 @@
<?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>

View file

@ -4,7 +4,9 @@
<string name="add_custom_token_title">Добавить токен</string>
<string name="add_tokens_title">Валюты</string>
<string name="address_qr_code_message_format">Отправляйте только %1$s (%2$s) в сети %3$s на этот адрес. Использование другой сети может привести к утрате средств.</string>
<string name="alert_button_how_to_scan">Как сканировать</string>
<string name="alert_button_request_support">Обратиться в поддержку</string>
<string name="alert_button_try_again">Попробовать снова</string>
<string name="alert_demo_feature_disabled">Эта функция недоступна в демонстрационном режиме</string>
<string name="alert_failed_to_send_transaction_message">Причина: %s</string>
<string name="alert_failed_to_send_transaction_title">Не могу отправить транзакцию</string>

View file

@ -4,7 +4,9 @@
<string name="add_custom_token_title">Add custom token</string>
<string name="add_tokens_title">Manage tokens</string>
<string name="address_qr_code_message_format">Send only %1$s (%2$s) from %3$s network to this address. Using other tokens and networks may result in loss of funds.</string>
<string name="alert_button_how_to_scan">How to scan</string>
<string name="alert_button_request_support">Request support</string>
<string name="alert_button_try_again">Try again</string>
<string name="alert_demo_feature_disabled">This feature is disabled in Demo mode</string>
<string name="alert_failed_to_send_transaction_message">Reason: %s</string>
<string name="alert_failed_to_send_transaction_title">Can\'t send a transaction</string>

View file

@ -2,7 +2,7 @@ package com.tangem.domain.redux
interface StateDialog {
data class ScanFailsDialog(val source: ScanFailsSource) : StateDialog
data class ScanFailsDialog(val source: ScanFailsSource, val onTryAgain: (() -> Unit)? = null) : StateDialog
enum class ScanFailsSource {
MAIN, SIGN_IN, SETTINGS, INTRO;

View file

@ -174,8 +174,8 @@ internal class DefaultWalletRouter(
reduxNavController.navigate(action = NavigationAction.NavigateTo(AppScreen.ManageTokens))
}
override fun openScanFailedDialog() {
reduxStateHolder.dispatchDialogShow(StateDialog.ScanFailsDialog(StateDialog.ScanFailsSource.MAIN))
override fun openScanFailedDialog(onTryAgain: () -> Unit) {
reduxStateHolder.dispatchDialogShow(StateDialog.ScanFailsDialog(StateDialog.ScanFailsSource.MAIN, onTryAgain))
}
private companion object {

View file

@ -59,5 +59,5 @@ internal interface InnerWalletRouter : WalletRouter {
fun openManageTokensScreen()
/** Open scan failed dialog */
fun openScanFailedDialog()
fun openScanFailedDialog(onTryAgain: () -> Unit)
}

View file

@ -165,7 +165,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
override fun onScanToUnlockWalletClick() {
analyticsEventHandler.send(MainScreen.UnlockWithCardScan)
openScanCardDialog()
}
private fun openScanCardDialog() {
viewModelScope.launch(dispatchers.main) {
scanCardToUnlockWalletClickHandler(walletId = stateHolder.getSelectedWalletId())
.onLeft { error ->
@ -175,7 +178,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
event = WalletEvent.ShowAlert(WalletAlertState.WrongCardIsScanned),
)
}
ScanCardToUnlockWalletError.ManyScanFails -> router.openScanFailedDialog()
ScanCardToUnlockWalletError.ManyScanFails -> router.openScanFailedDialog(::openScanCardDialog)
}
}
}