Updated on 2026-08-14
This commit is contained in:
commit
2cfb552d19
33 changed files with 571 additions and 131 deletions
|
|
@ -8,9 +8,11 @@ import com.tangem.tap.common.images.PicassoHelper
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.appReducer
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.config.ConfigManager
|
||||
import com.tangem.tap.domain.config.LocalLoader
|
||||
import com.tangem.tap.domain.config.RemoteLoader
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.config.FeaturesLocalLoader
|
||||
import com.tangem.tap.domain.configurable.config.FeaturesRemoteLoader
|
||||
import com.tangem.tap.domain.configurable.warningMessage.RemoteWarningLoader
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.network.NetworkConnectivity
|
||||
import com.tangem.tap.network.createMoshi
|
||||
import com.tangem.tap.persistence.PreferencesStorage
|
||||
|
|
@ -50,9 +52,11 @@ class TapApplication : Application() {
|
|||
|
||||
private fun loadConfigs() {
|
||||
val moshi = createMoshi()
|
||||
val localLoader = LocalLoader(this, moshi)
|
||||
val remoteLoader = RemoteLoader(moshi)
|
||||
val localLoader = FeaturesLocalLoader(this, moshi)
|
||||
val remoteLoader = FeaturesRemoteLoader(moshi)
|
||||
val configManager = ConfigManager(localLoader, remoteLoader)
|
||||
configManager.load { store.dispatch(GlobalAction.SetConfigManager(configManager)) }
|
||||
val warningsManager = WarningMessagesManager(RemoteWarningLoader(moshi))
|
||||
warningsManager.load { store.dispatch(GlobalAction.SetWarningManager(warningsManager)) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.tap.domain.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.features.details.redux.SecurityOption
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -18,5 +20,7 @@ sealed class GlobalAction : Action {
|
|||
}
|
||||
data class UpdateWalletSignedHashes(val walletSignedHashes: Int?) : GlobalAction()
|
||||
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
|
||||
data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction()
|
||||
data class HideWarningMessage(val warning: WarningMessage) : GlobalAction()
|
||||
data class UpdateSecurityOptions(val securityOption: SecurityOption) : GlobalAction()
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
|
@ -14,6 +18,19 @@ val globalMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
preferencesStorage.getAppCurrency()
|
||||
))
|
||||
}
|
||||
is GlobalAction.HideWarningMessage -> {
|
||||
store.state.globalState.warningManager?.let {
|
||||
if (it.hideWarning(action.warning)) {
|
||||
if (WarningMessagesManager.isAlreadySignedHashesWarning(action.warning)) {
|
||||
//TODO: No appropriate warningMessage identification. Make it better later
|
||||
store.dispatch(WalletAction.SaveCardId)
|
||||
}
|
||||
|
||||
store.dispatch(WalletAction.SetWarnings(it.getWarnings(WarningMessage.Location.MainScreen)))
|
||||
store.dispatch(SendAction.SetWarnings(it.getWarnings(WarningMessage.Location.SendScreen)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nextDispatch(action)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
is GlobalAction.SetConfigManager -> {
|
||||
globalState.copy(configManager = action.configManager)
|
||||
}
|
||||
is GlobalAction.SetWarningManager -> globalState.copy(warningManager = action.warningManager)
|
||||
is GlobalAction.HideWarningMessage -> globalState
|
||||
is GlobalAction.UpdateSecurityOptions -> {
|
||||
val card = when (action.securityOption) {
|
||||
SecurityOption.LongTap -> globalState.scanNoteResponse?.card?.copy(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import com.tangem.commands.common.network.TangemService
|
|||
import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY
|
||||
import com.tangem.tap.domain.PayIdManager
|
||||
import com.tangem.tap.domain.TapWalletManager
|
||||
import com.tangem.tap.domain.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
|
||||
import org.rekotlin.StateType
|
||||
|
|
@ -18,6 +19,7 @@ data class GlobalState(
|
|||
val tangemService: TangemService = TangemService(),
|
||||
val conversionRates: ConversionRates = ConversionRates(emptyMap()),
|
||||
val configManager: ConfigManager? = null,
|
||||
val warningManager: WarningMessagesManager? = null,
|
||||
val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY
|
||||
) : StateType
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
|||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.extensions.isNoAccountError
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
|
|
@ -84,6 +84,8 @@ class TapWalletManager {
|
|||
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card)
|
||||
}
|
||||
TapWorkarounds.updateCard(data.card)
|
||||
|
||||
store.state.globalState.warningManager?.setBlockchain(data.walletManager?.wallet?.blockchain)
|
||||
val configManager = store.state.globalState.configManager
|
||||
if (TapWorkarounds.isStart2Coin) {
|
||||
configManager?.turnOff(ConfigManager.isWalletPayIdEnabled)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.tap.domain.configurable
|
||||
|
||||
import com.tangem.wallet.BuildConfig
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface Loader<T> {
|
||||
fun load(onComplete: (T) -> Unit)
|
||||
|
||||
companion object {
|
||||
const val featuresName = "features_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
const val configValuesName = "config_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
const val warnings = "warnings_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tap.domain.config
|
||||
package com.tangem.tap.domain.configurable.config
|
||||
|
||||
import android.content.Context
|
||||
import com.google.firebase.ktx.Firebase
|
||||
|
|
@ -6,34 +6,24 @@ import com.google.firebase.remoteconfig.ktx.remoteConfig
|
|||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import com.tangem.tap.domain.configurable.Loader
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface ConfigLoader {
|
||||
fun loadConfig(onComplete: (ConfigModel) -> Unit)
|
||||
|
||||
companion object {
|
||||
const val featuresName = "features_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
const val configValuesName = "config_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LocalLoader(
|
||||
class FeaturesLocalLoader(
|
||||
private val context: Context,
|
||||
private val moshi: Moshi
|
||||
) : ConfigLoader {
|
||||
private val moshi: Moshi,
|
||||
) : Loader<ConfigModel> {
|
||||
|
||||
override fun loadConfig(onComplete: (ConfigModel) -> Unit) {
|
||||
override fun load(onComplete: (ConfigModel) -> Unit) {
|
||||
val config = try {
|
||||
val featureAdapter: JsonAdapter<FeatureModel> = moshi.adapter(FeatureModel::class.java)
|
||||
val valuesAdapter: JsonAdapter<ConfigValueModel> = moshi.adapter(ConfigValueModel::class.java)
|
||||
|
||||
val jsonFeatures = readAssetAsString(ConfigLoader.featuresName)
|
||||
val jsonConfigValues = readAssetAsString(ConfigLoader.configValuesName)
|
||||
val jsonFeatures = readAssetAsString(Loader.featuresName)
|
||||
val jsonConfigValues = readAssetAsString(Loader.configValuesName)
|
||||
|
||||
ConfigModel(featureAdapter.fromJson(jsonFeatures), valuesAdapter.fromJson(jsonConfigValues))
|
||||
} catch (ex: Exception) {
|
||||
|
|
@ -48,16 +38,16 @@ class LocalLoader(
|
|||
}
|
||||
}
|
||||
|
||||
class RemoteLoader(
|
||||
private val moshi: Moshi
|
||||
) : ConfigLoader {
|
||||
class FeaturesRemoteLoader(
|
||||
private val moshi: Moshi,
|
||||
) : Loader<ConfigModel> {
|
||||
|
||||
override fun loadConfig(onComplete: (ConfigModel) -> Unit) {
|
||||
override fun load(onComplete: (ConfigModel) -> Unit) {
|
||||
val emptyConfig = ConfigModel.empty()
|
||||
val remoteConfig = Firebase.remoteConfig
|
||||
remoteConfig.fetchAndActivate().addOnCompleteListener {
|
||||
if (it.isSuccessful) {
|
||||
val config = remoteConfig.getValue(ConfigLoader.featuresName)
|
||||
val config = remoteConfig.getValue(Loader.featuresName)
|
||||
val jsonConfig = config.asString()
|
||||
if (jsonConfig.isEmpty()) {
|
||||
onComplete(emptyConfig)
|
||||
|
|
@ -69,7 +59,7 @@ class RemoteLoader(
|
|||
onComplete(emptyConfig)
|
||||
}
|
||||
}.addOnFailureListener {
|
||||
FirebaseAnalyticsHandler.logException("remote_config_error", it)
|
||||
FirebaseAnalyticsHandler.logException("remote_config_error.features", it)
|
||||
onComplete(emptyConfig)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.domain.config
|
||||
package com.tangem.tap.domain.configurable.config
|
||||
|
||||
import com.tangem.tangem_sdk_new.ui.animation.VoidCallback
|
||||
import com.tangem.tap.domain.configurable.Loader
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -16,8 +17,8 @@ data class Config(
|
|||
)
|
||||
|
||||
class ConfigManager(
|
||||
private val localLoader: ConfigLoader,
|
||||
private val remoteLoader: ConfigLoader
|
||||
private val localLoader: Loader<ConfigModel>,
|
||||
private val remoteLoader: Loader<ConfigModel>
|
||||
) {
|
||||
|
||||
var config: Config = Config()
|
||||
|
|
@ -26,11 +27,11 @@ class ConfigManager(
|
|||
private var defaultConfig = Config()
|
||||
|
||||
fun load(onComplete: VoidCallback? = null) {
|
||||
localLoader.loadConfig { config ->
|
||||
localLoader.load { config ->
|
||||
setupFeature(config.features)
|
||||
setupKey(config.configValues)
|
||||
}
|
||||
remoteLoader.loadConfig { config ->
|
||||
remoteLoader.load { config ->
|
||||
setupFeature(config.features)
|
||||
onComplete?.invoke()
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tap.domain.config
|
||||
package com.tangem.tap.domain.configurable.config
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.tangem.tap.domain.configurable.warningMessage
|
||||
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.google.firebase.remoteconfig.ktx.remoteConfig
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.domain.configurable.Loader
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class RemoteWarningLoader(
|
||||
private val moshi: Moshi,
|
||||
) : Loader<List<WarningMessage>> {
|
||||
|
||||
override fun load(onComplete: (List<WarningMessage>) -> Unit) {
|
||||
val emptyConfig = listOf<WarningMessage>()
|
||||
val remoteConfig = Firebase.remoteConfig
|
||||
remoteConfig.fetchAndActivate().addOnCompleteListener {
|
||||
if (!it.isSuccessful) {
|
||||
onComplete(emptyConfig)
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
|
||||
val config = remoteConfig.getValue(Loader.warnings)
|
||||
val jsonConfig = config.asString()
|
||||
if (jsonConfig.isEmpty()) {
|
||||
onComplete(emptyConfig)
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
|
||||
val adapterType = Types.newParameterizedType(List::class.java, WarningMessage::class.java)
|
||||
val warningsAdapter: JsonAdapter<List<WarningMessage>> = moshi.adapter(adapterType)
|
||||
try {
|
||||
val warnings = warningsAdapter.fromJson(jsonConfig) ?: listOf()
|
||||
onComplete(warnings)
|
||||
} catch (ex: Exception) {
|
||||
handleError(ex)
|
||||
onComplete(emptyConfig)
|
||||
}
|
||||
}.addOnFailureListener {
|
||||
handleError(it)
|
||||
onComplete(emptyConfig)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleError(ex: Exception) {
|
||||
FirebaseAnalyticsHandler.logException("remote_config_error.warnings", ex)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.tangem.tap.domain.configurable.warningMessage
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class WarningMessage(
|
||||
val title: String,
|
||||
val message: String,
|
||||
val type: Type,
|
||||
val priority: Priority,
|
||||
val location: List<Location>,
|
||||
private val blockchains: List<String>?,
|
||||
val titleResId: Int? = null,
|
||||
val messageResId: Int? = null,
|
||||
val origin: Origin = Origin.Remote,
|
||||
) {
|
||||
val blockchainList: List<Blockchain>? by lazy {
|
||||
blockchains?.map { Blockchain.fromId(it.toUpperCase()) }
|
||||
}
|
||||
|
||||
|
||||
var isHidden = false
|
||||
|
||||
enum class Priority {
|
||||
@Json(name = "critical")
|
||||
Critical,
|
||||
|
||||
@Json(name = "warning")
|
||||
Warning,
|
||||
|
||||
@Json(name = "info")
|
||||
Info
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
@Json(name = "permanent")
|
||||
Permanent, // нельзя скрыть
|
||||
|
||||
@Json(name = "temporary")
|
||||
Temporary // можно скрыть (кнопка ОК)
|
||||
}
|
||||
|
||||
enum class Location {
|
||||
@Json(name = "main")
|
||||
MainScreen,
|
||||
|
||||
@Json(name = "send")
|
||||
SendScreen
|
||||
}
|
||||
|
||||
enum class Origin {
|
||||
Local, Remote
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package com.tangem.tap.domain.configurable.warningMessage
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tangem_sdk_new.ui.animation.VoidCallback
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class WarningMessagesManager(
|
||||
private val warningLoader: RemoteWarningLoader,
|
||||
) {
|
||||
|
||||
private var blockchain: Blockchain? = null
|
||||
private val warningsList: MutableList<WarningMessage> = mutableListOf()
|
||||
|
||||
fun load(onComplete: VoidCallback? = null) {
|
||||
warningLoader.load { remoteList ->
|
||||
warningsList.clear()
|
||||
warningsList.addAll(remoteList)
|
||||
sortByPriority()
|
||||
onComplete?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
fun setBlockchain(blockchain: Blockchain?) {
|
||||
this.blockchain = blockchain
|
||||
}
|
||||
|
||||
fun addWarning(warning: WarningMessage) {
|
||||
if (findWarning(warning) == null) {
|
||||
warningsList.add(warning)
|
||||
sortByPriority()
|
||||
}
|
||||
}
|
||||
|
||||
fun getWarnings(location: WarningMessage.Location): List<WarningMessage> {
|
||||
return warningsList
|
||||
.filter { !it.isHidden && it.location.contains(location) }
|
||||
.filter {
|
||||
val blockchainList = it.blockchainList
|
||||
when {
|
||||
blockchainList == null -> true
|
||||
blockchainList.contains(blockchain) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hideWarning(warning: WarningMessage): Boolean {
|
||||
val foundWarning = findWarning(warning)
|
||||
return when {
|
||||
foundWarning == null -> false
|
||||
foundWarning.type == WarningMessage.Type.Temporary -> {
|
||||
if (foundWarning.isHidden) {
|
||||
false
|
||||
} else {
|
||||
foundWarning.isHidden = true
|
||||
true
|
||||
}
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun removeWarnings(origin: WarningMessage.Origin) {
|
||||
warningsList.removeIf { it.origin == origin }
|
||||
sortByPriority()
|
||||
}
|
||||
|
||||
private fun sortByPriority() {
|
||||
warningsList.sortBy { it.priority.ordinal }
|
||||
}
|
||||
|
||||
private fun findWarning(warning: WarningMessage): WarningMessage? {
|
||||
return warningsList.firstOrNull { it == warning }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun devCardWarning(): WarningMessage = WarningMessage(
|
||||
"",
|
||||
"",
|
||||
type = WarningMessage.Type.Permanent,
|
||||
priority = WarningMessage.Priority.Critical,
|
||||
listOf(WarningMessage.Location.MainScreen),
|
||||
null,
|
||||
R.string.alert_title,
|
||||
R.string.alert_developer_card,
|
||||
WarningMessage.Origin.Local
|
||||
)
|
||||
|
||||
fun alreadySignedHashesWarning(): WarningMessage = WarningMessage(
|
||||
"",
|
||||
"",
|
||||
type = WarningMessage.Type.Temporary,
|
||||
priority = WarningMessage.Priority.Info,
|
||||
listOf(WarningMessage.Location.MainScreen),
|
||||
null,
|
||||
R.string.alert_title,
|
||||
R.string.alert_card_signed_transactions,
|
||||
WarningMessage.Origin.Local
|
||||
)
|
||||
|
||||
fun isAlreadySignedHashesWarning(warning: WarningMessage):Boolean {
|
||||
return warning.messageResId == R.string.alert_card_signed_transactions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.tap.common.redux.ErrorAction
|
||||
import com.tangem.tap.common.redux.ToastNotificationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
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.SendButtonState
|
||||
|
|
@ -146,4 +147,5 @@ sealed class SendAction : SendScreenAction {
|
|||
|
||||
object Hide : Dialog()
|
||||
}
|
||||
data class SetWarnings(val warningList: List<WarningMessage>) : SendAction()
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ private class SendReducer : SendInternalReducer {
|
|||
is SendAction.ChangeSendButtonState -> sendState.copy(sendButtonState = action.state)
|
||||
is SendAction.Dialog.ShowTezosWarningDialog -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.Hide -> sendState.copy(dialog = null)
|
||||
is SendAction.SetWarnings -> sendState.copy(sendWarningsList = action.warningList)
|
||||
else -> return sendState
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.tap.common.CurrencyConverter
|
|||
import com.tangem.tap.common.entities.TapCurrency
|
||||
import com.tangem.tap.common.text.DecimalDigitsInputFilter
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.StateType
|
||||
|
|
@ -37,6 +38,7 @@ data class SendState(
|
|||
val amountState: AmountState = AmountState(),
|
||||
val feeState: FeeState = FeeState(),
|
||||
val receiptState: ReceiptState = ReceiptState(),
|
||||
val sendWarningsList: List<WarningMessage> = listOf(),
|
||||
val sendButtonState: SendButtonState = SendButtonState.DISABLED,
|
||||
val dialog: SendAction.Dialog? = null
|
||||
) : SendScreenState {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ import android.view.inputmethod.EditorInfo
|
|||
import android.widget.EditText
|
||||
import androidx.core.view.postDelayed
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.tangem.Message
|
||||
import com.tangem.merchant.common.toggleWidget.ToggleWidget
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tangem_sdk_new.extensions.hideSoftKeyboard
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.entities.TapCurrency
|
||||
|
|
@ -22,6 +25,7 @@ import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
|
|||
import com.tangem.tap.common.snackBar.MaxAmountSnackbar
|
||||
import com.tangem.tap.common.text.truncateMiddleWith
|
||||
import com.tangem.tap.common.toggleWidget.*
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUi.*
|
||||
|
|
@ -30,10 +34,14 @@ import com.tangem.tap.features.send.redux.FeeActionUi.*
|
|||
import com.tangem.tap.features.send.redux.states.FeeType
|
||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||
import com.tangem.tap.features.send.ui.stateSubscribers.SendStateSubscriber
|
||||
import com.tangem.tap.features.wallet.ui.SpacesItemDecoration
|
||||
import com.tangem.tap.features.wallet.ui.WarningMessagesAdapter
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_send.*
|
||||
import kotlinx.android.synthetic.main.fragment_send.rv_warning_messages
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.*
|
||||
import kotlinx.android.synthetic.main.layout_send_address_payid.*
|
||||
import kotlinx.android.synthetic.main.layout_send_amount.*
|
||||
import kotlinx.android.synthetic.main.layout_send_fee.*
|
||||
|
|
@ -50,6 +58,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
lateinit var sendBtn: ToggleWidget
|
||||
|
||||
private lateinit var etAmountToSend: TextInputEditText
|
||||
private lateinit var warningsAdapter: WarningMessagesAdapter
|
||||
|
||||
private fun initSendButtonStates() {
|
||||
sendBtn = ToggleWidget(flSendButtonContainer, btnSend, progress, ProgressState.None())
|
||||
|
|
@ -70,6 +79,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
setupTransactionExtrasLayout()
|
||||
setupAmountLayout()
|
||||
setupFeeLayout()
|
||||
setupWarningMessages()
|
||||
|
||||
btnSend.setOnClickListener {
|
||||
store.dispatch(SendActionUi.SendAmountToRecipient(
|
||||
|
|
@ -227,6 +237,17 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupWarningMessages() {
|
||||
warningsAdapter = WarningMessagesAdapter()
|
||||
val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
rv_warning_messages.layoutManager = layoutManager
|
||||
rv_warning_messages.addItemDecoration(SpacesItemDecoration(rv_warning_messages.dpToPx(16f).toInt()))
|
||||
rv_warning_messages.adapter = warningsAdapter
|
||||
|
||||
val warnings = store.state.globalState.warningManager?.getWarnings(WarningMessage.Location.SendScreen) ?: listOf()
|
||||
store.dispatch(SendAction.SetWarnings(warnings))
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(sendSubscriber) { appState ->
|
||||
appState.skipRepeats { oldState, newState ->
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.tangem.tap.features.send.redux.states.*
|
|||
import com.tangem.tap.features.send.ui.FeeUiHelper
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.send.ui.dialogs.TezosWarningDialog
|
||||
import com.tangem.tap.features.wallet.ui.WarningMessagesAdapter
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.btn_expand_collapse.*
|
||||
|
|
@ -122,6 +123,12 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
sendFragment.sendBtn.setState(ProgressState.Progress(), true)
|
||||
}
|
||||
}
|
||||
|
||||
val rv = fg.rv_warning_messages
|
||||
val adapter = rv.adapter as? WarningMessagesAdapter ?: return
|
||||
|
||||
adapter.submitList(state.sendWarningsList)
|
||||
rv.show(state.sendWarningsList.isNotEmpty())
|
||||
}
|
||||
|
||||
private fun handleAddressPayIdState(fg: BaseStoreFragment, state: AddressPayIdState) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.tap.common.redux.ErrorAction
|
|||
import com.tangem.tap.common.redux.NotificationAction
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.twins.TwinCardNumber
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -34,7 +35,7 @@ sealed class WalletAction : Action {
|
|||
object CheckHashesCountOnline : WalletAction()
|
||||
object NeedToCheckHashesCountOnline : WalletAction()
|
||||
object ConfirmHashesCount : WalletAction()
|
||||
data class ShowWarning(val warningType: WarningType) : WalletAction()
|
||||
data class SetWarnings(val warningList: List<WarningMessage>) : WalletAction()
|
||||
object SaveCardId : WalletAction()
|
||||
|
||||
object UpdateWallet : WalletAction() {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import com.tangem.tap.common.redux.navigation.NavigationAction
|
|||
import com.tangem.tap.domain.PayIdManager
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.TopUpHelper
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.domain.extensions.toSendableAmounts
|
||||
import com.tangem.tap.domain.twins.TwinsHelper
|
||||
import com.tangem.tap.domain.twins.isTwinCard
|
||||
|
|
@ -172,13 +174,17 @@ class WalletMiddleware {
|
|||
}
|
||||
}
|
||||
is WalletAction.CheckIfWarningNeeded -> {
|
||||
val card = store.state.globalState.scanNoteResponse?.card
|
||||
val validator = store.state.globalState.scanNoteResponse?.walletManager
|
||||
as? SignatureCountValidator
|
||||
if (card != null && !preferencesStorage.wasCardScannedBefore(card.cardId)) {
|
||||
val result = checkIfWarningNeeded(card, validator)
|
||||
if (result != null) store.dispatch(WalletAction.ShowWarning(result))
|
||||
val globalState = store.state.globalState
|
||||
val validator = globalState.scanNoteResponse?.walletManager as? SignatureCountValidator
|
||||
globalState.scanNoteResponse?.card?.let { card ->
|
||||
store.state.globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local)
|
||||
if (card.getType() != CardType.Release) addWarningMessage(WarningMessagesManager.devCardWarning())
|
||||
if (!preferencesStorage.wasCardScannedBefore(card.cardId)) {
|
||||
checkIfWarningNeeded(card, validator)?.let { addWarningMessage(it) }
|
||||
}
|
||||
updateWarningMessages()
|
||||
}
|
||||
|
||||
}
|
||||
is WalletAction.CheckHashesCountOnline -> checkHashesCountOnline()
|
||||
is WalletAction.SaveCardId -> {
|
||||
|
|
@ -230,17 +236,13 @@ class WalletMiddleware {
|
|||
}
|
||||
|
||||
private fun checkIfWarningNeeded(
|
||||
card: Card, signatureCountValidator: SignatureCountValidator? = null
|
||||
): WarningType? {
|
||||
|
||||
if (card.getType() != CardType.Release) {
|
||||
return WarningType.DevCard
|
||||
}
|
||||
card: Card, signatureCountValidator: SignatureCountValidator? = null,
|
||||
): WarningMessage? {
|
||||
if (card.isTwinCard()) return null
|
||||
|
||||
return if (signatureCountValidator == null) {
|
||||
if (card.walletSignedHashes ?: 0 > 0) {
|
||||
WarningType.CardSignedHashesBefore
|
||||
WarningMessagesManager.alreadySignedHashesWarning()
|
||||
} else {
|
||||
store.dispatch(WalletAction.SaveCardId)
|
||||
null
|
||||
|
|
@ -272,14 +274,24 @@ class WalletMiddleware {
|
|||
}
|
||||
is SimpleResult.Failure ->
|
||||
if (result.error is BlockchainSdkError.SignatureCountNotMatched) {
|
||||
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
|
||||
addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true)
|
||||
} else if (card.walletSignedHashes ?: 0 > 0) {
|
||||
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
|
||||
addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addWarningMessage(warning: WarningMessage, autoUpdate: Boolean = false) {
|
||||
store.state.globalState.warningManager?.addWarning(warning)
|
||||
if (autoUpdate) updateWarningMessages()
|
||||
}
|
||||
|
||||
private fun updateWarningMessages() {
|
||||
val warningManager = store.state.globalState.warningManager ?: return
|
||||
store.dispatch(WalletAction.SetWarnings(warningManager.getWarnings(WarningMessage.Location.MainScreen)))
|
||||
}
|
||||
}
|
||||
|
||||
private class TopUpMiddleware {
|
||||
|
|
|
|||
|
|
@ -215,8 +215,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
)
|
||||
}
|
||||
is WalletAction.Send.Cancel -> newState = newState.copy(walletDialog = null)
|
||||
is WalletAction.ShowWarning ->
|
||||
newState = newState.copy(walletDialog = WalletDialog.WarningDialog(action.warningType))
|
||||
is WalletAction.SetWarnings -> newState = newState.copy(mainWarningsList = action.warningList)
|
||||
is WalletAction.NeedToCheckHashesCountOnline ->
|
||||
newState = newState.copy(hashesCountVerified = false)
|
||||
is WalletAction.ConfirmHashesCount ->
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.tap.common.entities.Button
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.twins.TwinCardNumber
|
||||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
|
||||
|
|
@ -27,6 +28,7 @@ data class WalletState(
|
|||
val mainButton: WalletMainButton = WalletMainButton.SendButton(false),
|
||||
val topUpState: TopUpState = TopUpState(),
|
||||
val twinCardsState: TwinCardsState? = null,
|
||||
val mainWarningsList: List<WarningMessage> = mutableListOf()
|
||||
) : StateType {
|
||||
val showDetails: Boolean =
|
||||
currencyData.status != com.tangem.tap.features.wallet.ui.BalanceStatus.EmptyCard &&
|
||||
|
|
@ -49,13 +51,9 @@ sealed class WalletDialog {
|
|||
|
||||
data class CreatePayIdDialog(val creatingPayIdState: CreatingPayIdState?) : WalletDialog()
|
||||
data class SelectAmountToSendDialog(val amounts: List<Amount>?) : WalletDialog()
|
||||
data class WarningDialog(val type: WarningType) : WalletDialog()
|
||||
data class TwinsOnboardingFragment(val secondCardId: String): WalletDialog()
|
||||
}
|
||||
|
||||
enum class WarningType { CardSignedHashesBefore, DevCard }
|
||||
|
||||
|
||||
enum class ProgressState { Loading, Done, Error }
|
||||
|
||||
enum class ErrorType { NoInternetConnection }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.activity.OnBackPressedCallback
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.squareup.picasso.Picasso
|
||||
|
|
@ -15,6 +16,7 @@ import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressType
|
|||
import com.tangem.blockchain.blockchains.cardano.CardanoAddressType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -24,7 +26,6 @@ import com.tangem.tap.features.wallet.redux.*
|
|||
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.PayIdDialog
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.QrDialog
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.WarningDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.card_balance.*
|
||||
|
|
@ -41,7 +42,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
private var dialog: Dialog? = null
|
||||
private var snackbar: Snackbar? = null
|
||||
|
||||
private lateinit var viewAdapter: PendingTransactionsAdapter
|
||||
private lateinit var pendingTransactionAdapter: PendingTransactionsAdapter
|
||||
private lateinit var warningsAdapter: WarningMessagesAdapter
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -78,14 +80,22 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
}
|
||||
setupWarningsRecyclerView()
|
||||
setupTransactionsRecyclerView()
|
||||
}
|
||||
|
||||
private fun setupWarningsRecyclerView() {
|
||||
warningsAdapter = WarningMessagesAdapter()
|
||||
val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
rv_warning_messages.layoutManager = layoutManager
|
||||
rv_warning_messages.addItemDecoration(SpacesItemDecoration(rv_warning_messages.dpToPx(16f).toInt()))
|
||||
rv_warning_messages.adapter = warningsAdapter
|
||||
}
|
||||
|
||||
private fun setupTransactionsRecyclerView() {
|
||||
viewAdapter = PendingTransactionsAdapter()
|
||||
pendingTransactionAdapter = PendingTransactionsAdapter()
|
||||
rv_pending_transaction.layoutManager = LinearLayoutManager(context)
|
||||
rv_pending_transaction.adapter = viewAdapter
|
||||
rv_pending_transaction.adapter = pendingTransactionAdapter
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -122,12 +132,11 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
setupAddressCard(state)
|
||||
setupCardImage(state.cardImage)
|
||||
|
||||
viewAdapter.submitList(state.pendingTransactions)
|
||||
if (state.pendingTransactions.isEmpty()) {
|
||||
rv_pending_transaction.hide()
|
||||
} else {
|
||||
rv_pending_transaction.show()
|
||||
}
|
||||
warningsAdapter.submitList(state.mainWarningsList)
|
||||
rv_warning_messages.show(state.mainWarningsList.isNotEmpty())
|
||||
|
||||
pendingTransactionAdapter.submitList(state.pendingTransactions)
|
||||
rv_pending_transaction.show(state.pendingTransactions.isNotEmpty())
|
||||
|
||||
handleDialogs(state.walletDialog)
|
||||
|
||||
|
|
@ -292,11 +301,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
this.show(walletDialog.amounts)
|
||||
}
|
||||
}
|
||||
is WalletDialog.WarningDialog -> {
|
||||
if (dialog == null) dialog = WarningDialog(requireContext()).apply {
|
||||
this.show(walletDialog.type)
|
||||
}
|
||||
}
|
||||
null -> {
|
||||
dialog?.dismiss()
|
||||
dialog = null
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
package com.tangem.tap.features.wallet.ui
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.layout_warning.view.*
|
||||
|
||||
class WarningMessagesAdapter : ListAdapter<WarningMessage, WarningMessageVH>(DiffUtilCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WarningMessageVH {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val layout = inflater.inflate(R.layout.layout_warning, parent, false)
|
||||
return WarningMessageVH(layout)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: WarningMessageVH, position: Int) {
|
||||
holder.bind(currentList[position])
|
||||
}
|
||||
|
||||
object DiffUtilCallback : DiffUtil.ItemCallback<WarningMessage>() {
|
||||
override fun areContentsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = oldItem == newItem
|
||||
|
||||
override fun areItemsTheSame(oldItem: WarningMessage, newItem: WarningMessage) = oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
||||
class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
fun bind(warning: WarningMessage) {
|
||||
setBgColor(warning.priority)
|
||||
setText(warning)
|
||||
setupOkButton(warning)
|
||||
}
|
||||
|
||||
private fun setText(warning: WarningMessage) {
|
||||
fun getString(resId: Int?, default: String) = if (resId == null) default else view.getString(resId)
|
||||
|
||||
view.tv_title.text = getString(warning.titleResId, warning.title)
|
||||
view.tv_message.text = getString(warning.messageResId, warning.message)
|
||||
}
|
||||
|
||||
private fun setBgColor(priority: WarningMessage.Priority) {
|
||||
val color = when (priority) {
|
||||
WarningMessage.Priority.Info -> R.color.warning_info
|
||||
WarningMessage.Priority.Warning -> R.color.warning_warning
|
||||
WarningMessage.Priority.Critical -> R.color.warning_critical
|
||||
}
|
||||
view.card_view.setCardBackgroundColor(view.context.resources.getColor(color))
|
||||
}
|
||||
|
||||
private fun setupOkButton(warning: WarningMessage) {
|
||||
view.btn_got_it.show(warning.type == WarningMessage.Type.Temporary)
|
||||
view.btn_got_it.setOnClickListener {
|
||||
store.dispatch(GlobalAction.HideWarningMessage(warning))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SpacesItemDecoration(private val spacePx: Int) : ItemDecoration() {
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
outRect.left = spacePx
|
||||
outRect.right = spacePx
|
||||
|
||||
outRect.top = spacePx / 2
|
||||
outRect.top = spacePx / 2
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package com.tangem.tap.features.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WarningType
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class WarningDialog(context: Context) : AlertDialog(context) {
|
||||
|
||||
private val dialog: AlertDialog = Builder(context)
|
||||
.setTitle(context.getString(R.string.common_warning))
|
||||
.setPositiveButton(context.getString(R.string.common_ok)) { _, _ ->
|
||||
dismiss()
|
||||
}.setOnDismissListener {
|
||||
store.dispatch(WalletAction.SaveCardId)
|
||||
store.dispatch(WalletAction.HideDialog)
|
||||
}
|
||||
.create()
|
||||
|
||||
fun show(warningType: WarningType) {
|
||||
val messageRes = when (warningType) {
|
||||
WarningType.CardSignedHashesBefore -> R.string.alert_card_signed_transactions
|
||||
WarningType.DevCard -> R.string.alert_developer_card
|
||||
}
|
||||
dialog.setMessage(dialog.context.getString(messageRes))
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,13 @@
|
|||
android:layout_marginBottom="24dp"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_warning_messages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/llBottomButtonContainer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -92,14 +99,14 @@
|
|||
<FrameLayout
|
||||
android:id="@+id/flSendButtonContainer"
|
||||
android:layout_width="0dp"
|
||||
android:paddingBottom="33dp"
|
||||
android:clipToPadding="false"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginStart="8dp">
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="33dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnSend"
|
||||
|
|
|
|||
|
|
@ -65,35 +65,47 @@
|
|||
android:id="@+id/iv_twin_card"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="30dp"
|
||||
android:src="@drawable/shape_chip"
|
||||
android:elevation="3dp"
|
||||
android:layout_marginStart="25dp"
|
||||
android:elevation="3dp"
|
||||
android:src="@drawable/shape_chip"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_card"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_card"
|
||||
app:layout_constraintTop_toBottomOf="@id/iv_card"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_card"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/iv_card" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_twin_card_number"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_twin_card"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_twin_card"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_twin_card"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_twin_card"
|
||||
tools:text="Card 2 of 2"
|
||||
android:elevation="3dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/buttonGray"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"/>
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_twin_card"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_twin_card"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_twin_card"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_twin_card"
|
||||
tools:text="Card 2 of 2" />
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier"
|
||||
app:barrierDirection="bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="iv_card,iv_twin_card"/>
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="iv_card,iv_twin_card" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_warning_messages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:minHeight="0dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_pending_transaction"
|
||||
|
|
@ -102,7 +114,9 @@
|
|||
android:layout_marginTop="12dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier" />
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_card_balance"
|
||||
|
|
@ -124,15 +138,15 @@
|
|||
layout="@layout/layout_wallet_long_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:visibility="gone"/>
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_buttons_short"
|
||||
layout="@layout/layout_wallet_short_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
62
app/src/main/res/layout/layout_warning.xml
Normal file
62
app/src/main/res/layout/layout_warning.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
app:cardBackgroundColor="@color/accent"
|
||||
app:cardCornerRadius="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="Test title"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_message"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Test text messaging, or texting, is the act of composing and sending electronic messages, typically consisting of alphabetic and numeric characters, between"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_title"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:lineHeight="18dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_got_it"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/how_to_got_it_button"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@android:color/white"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_message" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
|
@ -95,7 +95,8 @@
|
|||
<string name="details_manage_security_access_code">Zugangscode</string>
|
||||
<string name="details_manage_security_access_code_description">Sie müssen den richtigen Zugangscode eingeben, bevor Sie die Karte scannen.</string>
|
||||
<string name="alert_old_device_this_card">Sie können NFC-Probleme mit einigen iPhone 7/7+ während der Extraktion haben</string>
|
||||
<string name="alert_card_signed_transactions">Warnung: Diese Karte wurde früher bereits aufgeladen und Transaktionen wurden damit signiert. Ziehen Sie eine sofortige Auszahlung aller Beträge in Betracht, wenn Sie diese Karte von einer nicht vertrauenswürdigen Quelle erhalten haben.</string>
|
||||
<string name="alert_card_signed_transactions">Diese Karte wurde früher bereits aufgeladen und Transaktionen wurden damit signiert. Ziehen Sie eine sofortige Auszahlung aller Beträge in Betracht, wenn Sie diese Karte von einer nicht vertrauenswürdigen Quelle erhalten haben.</string>
|
||||
<string name="alert_title">Warnung</string>
|
||||
|
||||
<string name="alert_unsupported_card">Diese Karte ist für die Zusammenarbeit mit Tangem Tap nicht geeignet</string>
|
||||
<string name="alert_developer_card">Die von Ihnen gescannte Karte ist eine Entwicklungskarte. Akzeptieren Sie sie nicht als Zahlungsmittel</string>
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@
|
|||
<string name="details_manage_security_access_code">Code d’accès </string>
|
||||
<string name="details_manage_security_access_code_description">Vous devrez entrer le mot de passe correct avant de scanner la carte </string>
|
||||
<string name="alert_old_device_this_card">Vous pouvez rencontrer des problèmes NFC avec certains iPhone 7/7 + lors de l’extraction </string>
|
||||
<string name="alert_card_signed_transactions">Attention: cette carte a déjà été rechargée et a signé des transactions avant. Envisagez la possibilité de retirer tous les fonds immédiatement si vous avez reçu cette carte d\'une source non fiable.</string>
|
||||
<string name="alert_card_signed_transactions">Cette carte a déjà été rechargée et a signé des transactions avant. Envisagez la possibilité de retirer tous les fonds immédiatement si vous avez reçu cette carte d\'une source non fiable.</string>
|
||||
<string name="alert_title">Attention</string>
|
||||
<string name="alert_unsupported_card">Cette carte n\'est pas conçue pour fonctionner avec Tangem Tap </string>
|
||||
<string name="alert_developer_card">La carte que vous avez scannée est une carte de développement. Ne l\'acceptez pas comme paiement </string>
|
||||
<string name="alert_old_card">Les cartes Tangem émises avant septembre 2019 ne peuvent actuellement pas être extraites à l\'aide de l\'iPhone. Nous travaillons activement avec Apple pour rendre cela possible dans les futures versions d\'iOS. </string>
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@
|
|||
<string name="details_manage_security_access_code">Codice di accesso</string>
|
||||
<string name="details_manage_security_access_code_description">Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto</string>
|
||||
<string name="alert_old_device_this_card">Potresti riscontrare problemi con l\'NFC su alcuni iPhone 7/7 + durante la rimozione</string>
|
||||
<string name="alert_card_signed_transactions">Attenzione: questa carta è già stata ricaricata e ha firmato transazioni in passato. Valuta la possibilità di prelevare immediatamente tutti i fondi se hai ricevuto questa carta da una fonte inaffidabile.</string>
|
||||
<string name="alert_card_signed_transactions">Questa carta è già stata ricaricata e ha firmato transazioni in passato. Valuta la possibilità di prelevare immediatamente tutti i fondi se hai ricevuto questa carta da una fonte inaffidabile.</string>
|
||||
<string name="alert_title">Attenzione</string>
|
||||
<string name="alert_unsupported_card">Questa carta non è progettata per funzionare con Tangem Tap</string>
|
||||
<string name="alert_developer_card">La carta che hai scansionato è una carta di sviluppo. Non utilizzarla come strumento di pagamento</string>
|
||||
<string name="alert_old_card">Le schede emesse prima di settembre 2019 non possono attualmente essere utilizzate con un iPhone. Stiamo lavorando a stretto contatto con Apple per renderle disponibili nelle future versioni di iOS. </string>
|
||||
|
|
|
|||
|
|
@ -43,5 +43,8 @@
|
|||
<color name="blue3">#CBE4FF</color>
|
||||
<color name="blue_pale">#E0E6FA</color>
|
||||
|
||||
<color name="warning_info">#1C1C1E</color>
|
||||
<color name="warning_warning">#FFB71B</color>
|
||||
<color name="warning_critical">#CA0F03</color>
|
||||
|
||||
</resources>
|
||||
|
|
@ -107,7 +107,8 @@
|
|||
<string name="details_manage_security_access_code_description">You will have to submit the correct access code before scanning the card</string>
|
||||
|
||||
<string name="alert_old_device_this_card">You may experience NFC problems with some iPhone 7/7+ during the extraction</string>
|
||||
<string name="alert_card_signed_transactions">Warning: This card has been already topped up and signed transactions in the past. Consider immediate withdrawal of all funds if you have received this card from an untrusted source.</string>
|
||||
<string name="alert_card_signed_transactions">This card has been already topped up and signed transactions in the past. Consider immediate withdrawal of all funds if you have received this card from an untrusted source.</string>
|
||||
<string name="alert_title">Warning</string>
|
||||
<string name="alert_unsupported_card">This card it is not designed to work with Tangem Tap</string>
|
||||
<string name="alert_developer_card">The card you scanned is a development card. Don’t accept it as a payment</string>
|
||||
<string name="alert_old_card">Tangem cards manufactured before September 2019 cannot currently be extracted with an iPhone. We’re working hard with Apple to make it possible in future versions of iOS.</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue