Updated on 2026-08-14

This commit is contained in:
Tangem 2020-11-14 08:44:33 +03:00
commit e421ea721d
45 changed files with 1130 additions and 358 deletions

View file

@ -70,17 +70,12 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation 'com.tangem:blockchain:1.98.0'
implementation('com.tangem:core') {
version {
strictly '1.73.0'
}
}
implementation('com.tangem:sdk:') {
version {
strictly '1.73.0'
}
}
implementation 'com.tangem:blockchain:1.108.0'
implementation 'com.tangem:core:1.80.0'
implementation 'com.tangem:sdk:1.80.0'
// WebView
implementation "androidx.browser:browser:1.2.0"
//lifecycle
implementation "androidx.lifecycle:lifecycle-runtime:2.2.0"
@ -101,7 +96,9 @@ dependencies {
implementation 'com.squareup.picasso:picasso:2.71828'
// Firebase
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
implementation platform('com.google.firebase:firebase-bom:26.0.0')
implementation 'com.google.firebase:firebase-crashlytics'
implementation 'com.google.firebase:firebase-analytics-ktx'
testImplementation 'junit:junit:4.13'
testImplementation "com.google.truth:truth:1.0.1"

View file

@ -14,6 +14,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

View file

@ -5,7 +5,6 @@ import android.content.pm.ActivityInfo
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import com.tangem.CardFilter
import com.tangem.Config
@ -78,7 +77,7 @@ class MainActivity : AppCompatActivity() {
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
Handler(mainLooper).postDelayed( { handleBackgroundScan(intent) } , 200)
handleBackgroundScan(intent)
}
private fun handleBackgroundScan(intent: Intent?) {
@ -88,6 +87,7 @@ class MainActivity : AppCompatActivity() {
val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
if (tag != null) {
intent.action = null
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home, false))
store.dispatch(HomeAction.ReadCard)
}
}

View file

@ -2,5 +2,8 @@ package com.tangem.tap
object TapConfig {
const val usePayId: Boolean = true
const val useTopUp: Boolean = false
const val coinMarketCapKey = "f6622117-c043-47a0-8975-9d673ce484de"
const val moonPayApiKey = "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE"
const val moonPayApiSecretKey = "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C"
}

View file

@ -0,0 +1,7 @@
package com.tangem.tap.common.analytics
enum class AnalyticsEvent(val event: String) {
CARD_IS_SCANNED("card_is_scanned"),
TRANSACTION_IS_SENT("transaction_is_sent"),
READY_TO_SCAN("ready_to_scan"),
}

View file

@ -0,0 +1,7 @@
package com.tangem.tap.common.analytics
import com.tangem.commands.Card
interface AnalyticsHandler {
fun triggerEvent(event: AnalyticsEvent, card: Card?)
}

View file

@ -0,0 +1,29 @@
package com.tangem.tap.common.analytics
import android.os.Bundle
import androidx.core.os.bundleOf
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.tangem.commands.Card
object FirebaseAnalyticsHandler: AnalyticsHandler {
override fun triggerEvent(event: AnalyticsEvent, card: Card?) {
Firebase.analytics
.logEvent(event.event, setCardData(card))
}
private fun setCardData(card: Card?): Bundle {
if (card == null) return bundleOf()
return bundleOf(
AnalyticsParam.BLOCKCHAIN.param to card.cardData?.blockchainName,
AnalyticsParam.BATCH_ID.param to card.cardData?.batchId,
AnalyticsParam.FIRMWARE.param to card.firmwareVersion
)
}
private enum class AnalyticsParam(val param: String) {
BLOCKCHAIN("blockchain"),
BATCH_ID("batch_id"),
FIRMWARE("firmware"),
}
}

View file

@ -11,6 +11,7 @@ import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
import com.tangem.tap.features.home.HomeFragment
import com.tangem.tap.features.send.ui.SendFragment
import com.tangem.tap.features.wallet.ui.WalletFragment
import com.tangem.tap.features.wallet.ui.topup.TopUpFragment
import com.tangem.wallet.R
fun FragmentActivity.openFragment(screen: AppScreen, addToBackStack: Boolean = true) {
@ -39,6 +40,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
return when (screen) {
AppScreen.Home -> HomeFragment()
AppScreen.Wallet -> WalletFragment()
AppScreen.TopUp -> TopUpFragment()
AppScreen.Send -> SendFragment()
AppScreen.Details -> DetailsFragment()
AppScreen.DetailsConfirm -> DetailsConfirmFragment()

View file

@ -8,12 +8,12 @@ import com.tangem.tap.features.details.redux.DetailsMiddleware
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.disclaimer.redux.DisclaimerMiddleware
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
import com.tangem.tap.features.home.redux.HomeMiddleware
import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.home.redux.homeMiddleware
import com.tangem.tap.features.send.redux.middlewares.sendMiddleware
import com.tangem.tap.features.send.redux.states.SendState
import com.tangem.tap.features.wallet.redux.WalletMiddleware
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.walletMiddleware
import org.rekotlin.Middleware
import org.rekotlin.StateType
@ -31,7 +31,9 @@ data class AppState(
fun getMiddleware(): List<Middleware<AppState>> {
return listOf(
logMiddleware, navigationMiddleware, notificationsMiddleware, globalMiddleware,
homeMiddleware, walletMiddleware, sendMiddleware,
HomeMiddleware().homeMiddleware,
WalletMiddleware().walletMiddleware,
sendMiddleware,
DetailsMiddleware().detailsMiddleware,
DisclaimerMiddleware().disclaimerMiddleware
)

View file

@ -9,4 +9,4 @@ data class NavigationState(
val activity: WeakReference<FragmentActivity>? = null
) : StateType
enum class AppScreen { Home, Wallet, Send, Details, DetailsConfirm, DetailsSecurity, Disclaimer }
enum class AppScreen { Home, Wallet, TopUp, Send, Details, DetailsConfirm, DetailsSecurity, Disclaimer }

View file

@ -7,6 +7,8 @@ import com.tangem.common.CompletionResult
import com.tangem.common.extensions.CardType
import com.tangem.common.extensions.calculateSha256
import com.tangem.tangem_sdk_new.extensions.init
import com.tangem.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.AnalyticsHandler
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
import com.tangem.tap.domain.tasks.ScanNoteResponse
import com.tangem.tap.domain.tasks.ScanNoteTask
@ -22,7 +24,8 @@ class TangemSdkManager(val activity: ComponentActivity) {
activity, Config(cardFilter = CardFilter(EnumSet.allOf(CardType::class.java)))
)
suspend fun scanNote(): CompletionResult<ScanNoteResponse> {
suspend fun scanNote(analyticsHandler: AnalyticsHandler): CompletionResult<ScanNoteResponse> {
analyticsHandler.triggerEvent(AnalyticsEvent.READY_TO_SCAN, null)
return runTaskAsyncReturnOnMain(ScanNoteTask(),
initialMessage = Message(activity.getString(R.string.initial_message_scan_header)))
}

View file

@ -6,6 +6,8 @@ import com.tangem.commands.CardStatus
import com.tangem.commands.common.network.Result
import com.tangem.common.extensions.toHexString
import com.tangem.tap.TapConfig
import com.tangem.tap.common.analytics.AnalyticsEvent
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
@ -54,7 +56,8 @@ class TapWalletManager {
}
withContext(Dispatchers.Main) {
when (result) {
is Result.Success -> store.dispatch(WalletAction.UpdateWallet.Success(result.data))
is Result.Success ->
store.dispatch(WalletAction.UpdateWallet.Success(result.data))
is Result.Failure ->
store.dispatch(WalletAction.UpdateWallet.Failure(result.error?.localizedMessage))
}
@ -77,7 +80,10 @@ class TapWalletManager {
handleFiatRatesResult(results)
}
suspend fun onCardScanned(data: ScanNoteResponse) {
suspend fun onCardScanned(data: ScanNoteResponse, addAnalyticsEvent: Boolean = false) {
if (addAnalyticsEvent) {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card)
}
tapWorkarounds = TapWorkarounds(data.card)
withContext(Dispatchers.Main) {
store.dispatch(WalletAction.ResetState)
@ -95,7 +101,10 @@ class TapWalletManager {
store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection))
return@withContext
}
store.dispatch(WalletAction.LoadWallet)
store.dispatch(WalletAction.LoadWallet(
data.walletManager.wallet, data.verifyResponse?.artworkInfo?.id,
tapWorkarounds?.isStart2Coin != true && TapConfig.useTopUp
))
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
store.dispatch(WalletAction.LoadFiatRate)
store.dispatch(WalletAction.LoadPayId)
@ -159,12 +168,12 @@ class TapWalletManager {
when (result) {
is Result.Success -> {
val payId = result.data
if (tapWorkarounds?.isPayIdEnabled() == false) {
store.dispatch(WalletAction.DisablePayId)
return@withContext
}
if (payId == null) {
if (tapWorkarounds?.isPayIdCreationEnabled() == false) {
store.dispatch(WalletAction.DisablePayId)
} else {
store.dispatch(WalletAction.LoadPayId.NotCreated)
}
store.dispatch(WalletAction.LoadPayId.NotCreated)
} else {
store.dispatch(WalletAction.LoadPayId.Success(payId))
}

View file

@ -1,12 +1,14 @@
package com.tangem.tap.domain
import com.tangem.commands.Card
import java.util.*
class TapWorkarounds(val card: Card) {
private val isStart2Coin: Boolean = card.cardData?.issuerName == START_2_COIN_ISSUER
val isStart2Coin: Boolean =
card.cardData?.issuerName?.toLowerCase(Locale.US) == START_2_COIN_ISSUER
fun isPayIdCreationEnabled(): Boolean {
fun isPayIdEnabled(): Boolean {
if (isStart2Coin) return false
return true
}

View file

@ -0,0 +1,44 @@
package com.tangem.tap.domain
import android.net.Uri
import com.tangem.tap.TapConfig
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import org.spongycastle.util.encoders.Base64
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
class TopUpHelper {
companion object {
const val REDIRECT_URL = "https://success.tangem.com"
private const val BASE_URL = "https://buy-staging.moonpay.io"
private const val API_KEY_PATH = "?apiKey="
private const val CURRENCY_PATH = "&currencyCode="
private const val WALLET_ADDRESS_PATH = "&walletAddress="
private const val REDIRECT_URL_PATH = "&redirectUrl="
private const val SIGNATURE_PATH = "&signature="
fun getUrl(cryptoCurrencyName: CryptoCurrencyName, walletAddress: String): String {
val originalQuery = API_KEY_PATH + TapConfig.moonPayApiKey.urlEncode() +
CURRENCY_PATH + cryptoCurrencyName.urlEncode() +
WALLET_ADDRESS_PATH + walletAddress.urlEncode() +
REDIRECT_URL_PATH + REDIRECT_URL.urlEncode()
val signature = createSignature(originalQuery, TapConfig.moonPayApiSecretKey)
return BASE_URL + originalQuery + SIGNATURE_PATH + signature.urlEncode()
}
private fun String.urlEncode(): String {
return Uri.encode(this)
}
private fun createSignature(data: String, key: String): String {
val sha256Hmac = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(key.toByteArray(), "HmacSHA256")
sha256Hmac.init(secretKey)
return Base64.toBase64String(sha256Hmac.doFinal(data.toByteArray()))
}
}
}

View file

@ -4,6 +4,7 @@ import android.content.Intent
import android.net.Uri
import androidx.core.content.ContextCompat.startActivity
import com.tangem.common.CompletionResult
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
@ -17,61 +18,54 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.rekotlin.Middleware
val homeMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
when (action) {
is HomeAction.CheckIfFirstLaunch -> {
store.dispatch(
HomeAction.CheckIfFirstLaunch.Result(preferencesStorage.isFirstLaunch())
)
}
is HomeAction.ReadCard -> {
scope.launch {
val result = tangemSdkManager.scanNote()
withContext(Dispatchers.Main) {
when (result) {
is CompletionResult.Success -> {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.state.globalState.tapWalletManager.onCardScanned(result.data)
showDisclaimerOrNavigateToWallet()
class HomeMiddleware {
val homeMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
when (action) {
is HomeAction.CheckIfFirstLaunch -> {
store.dispatch(
HomeAction.CheckIfFirstLaunch.Result(preferencesStorage.isFirstLaunch())
)
}
is HomeAction.ReadCard -> {
scope.launch {
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler)
withContext(Dispatchers.Main) {
when (result) {
is CompletionResult.Success -> {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.state.globalState.tapWalletManager.onCardScanned(result.data)
showDisclaimerOrNavigateToWallet()
}
}
}
}
}
is HomeAction.GoToShop -> {
val uri = Uri.parse(CARD_SHOP_URI)
val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(action.context, intent, null)
}
}
is HomeAction.GoToShop -> {
val uri = Uri.parse(CARD_SHOP_URI)
val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(action.context, intent, null)
}
next(action)
}
next(action)
}
}
}
private fun showDisclaimerOrNavigateToWallet() {
if (preferencesStorage.wasDisclaimerAccepted()) {
navigateToWallet()
} else {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
}
private fun navigateToWallet() {
if (store.state.navigationState.backStack.isNotEmpty()) {
val currentScreen = store.state.navigationState.backStack.last()
if (currentScreen == AppScreen.Home) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
} else if (currentScreen != AppScreen.Wallet) {
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
private fun showDisclaimerOrNavigateToWallet() {
if (preferencesStorage.wasDisclaimerAccepted()) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
} else {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
} else {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
}
companion object {
private const val CARD_SHOP_URI =
"https://shop.tangem.com/?afmc=1i&utm_campaign=1i&utm_source=leaddyno&utm_medium=affiliate"
}
}
private const val CARD_SHOP_URI = "https://shop.tangem.com/?afmc=1i&utm_campaign=1i&utm_source=leaddyno&utm_medium=affiliate"

View file

@ -4,6 +4,9 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.blockchain.common.*
import com.tangem.blockchain.extensions.Result
import com.tangem.blockchain.extensions.Signer
import com.tangem.commands.Card
import com.tangem.tap.common.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
@ -47,6 +50,7 @@ private fun verifyAndSendTransaction(
) {
val sendState = appState?.sendState ?: return
val walletManager = appState.globalState.scanNoteResponse?.walletManager ?: return
val card = appState.globalState.scanNoteResponse.card
val recipientAddress = sendState.addressPayIdState.recipientWalletAddress ?: return
val typedAmount = sendState.amountState.amountToExtract ?: return
val feeAmount = sendState.feeState.currentFee ?: return
@ -62,14 +66,14 @@ private fun verifyAndSendTransaction(
dispatch(AmountAction.SetAmount(typedAmount.value!!.minus(reduceAmount), false))
dispatch(AmountActionUi.CheckAmountToSend)
}, sendAllCallback = {
sendTransaction(action, walletManager, amountToSend, feeAmount, recipientAddress, dispatch)
sendTransaction(action, walletManager, amountToSend, feeAmount, recipientAddress, card, dispatch)
}, reduceAmount))
}
transactionErrors.isNotEmpty() -> {
dispatch(SendAction.SendError(createValidateTransactionError(transactionErrors, walletManager)))
}
else -> {
sendTransaction(action, walletManager, amountToSend, feeAmount, recipientAddress, dispatch)
sendTransaction(action, walletManager, amountToSend, feeAmount, recipientAddress, card, dispatch)
}
}
}
@ -80,6 +84,7 @@ private fun sendTransaction(
amountToSend: Amount,
feeAmount: Amount,
recipientAddress: String,
card: Card,
dispatch: (Action) -> Unit
) {
dispatch(SendAction.ChangeSendButtonState(SendButtonState.PROGRESS))
@ -91,6 +96,7 @@ private fun sendTransaction(
withContext(Dispatchers.Main) {
when (result) {
is Result.Success -> {
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.TRANSACTION_IS_SENT, card)
dispatch(SendAction.SendSuccess)
dispatch(GlobalAction.UpdateWalletSignedHashes(result.data.walletSignedHashes))
dispatch(WalletAction.UpdateWallet)

View file

@ -20,7 +20,9 @@ sealed class WalletAction : Action {
data class Failure(val error: TapError) : WalletAction()
}
object LoadWallet : WalletAction() {
data class LoadWallet(
val wallet: Wallet, val artworkId: String?, val allowTopUp: Boolean
) : WalletAction() {
data class Success(val wallet: Wallet) : WalletAction()
data class NoAccount(val amountToCreateAccount: String) : WalletAction()
data class Failure(val errorMessage: String? = null) : WalletAction()
@ -50,7 +52,7 @@ sealed class WalletAction : Action {
object Failure : WalletAction()
}
object DisablePayId: WalletAction()
object DisablePayId : WalletAction()
data class LoadArtwork(val card: Card, val artworkId: String?) : WalletAction() {
data class Success(val artwork: Artwork) : WalletAction()
@ -85,4 +87,10 @@ sealed class WalletAction : Action {
data class ExploreAddress(val context: Context) : WalletAction()
object CreateWallet : WalletAction()
object EmptyWallet : WalletAction()
sealed class TopUpAction : WalletAction() {
data class TopUp(val context: Context, val toolbarColor: Int?) : TopUpAction()
data class Start(val url: String, val redirectUrl: String) : TopUpAction()
data class Finish(val topUpCompleted: Boolean) : TopUpAction()
}
}

View file

@ -11,12 +11,14 @@ import com.tangem.common.CompletionResult
import com.tangem.common.extensions.CardType
import com.tangem.common.extensions.getType
import com.tangem.common.extensions.toHexString
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
import com.tangem.tap.common.extensions.copyToClipboard
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.PayIdManager
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.TopUpHelper
import com.tangem.tap.domain.extensions.toSendableAmounts
import com.tangem.tap.features.send.redux.PrepareSendScreen
import com.tangem.tap.features.wallet.models.toPendingTransactions
@ -32,210 +34,239 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.rekotlin.Action
import org.rekotlin.Middleware
import timber.log.Timber
class WalletMiddleware {
private val topUpMiddleware = TopUpMiddleware()
val walletMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
when (action) {
is WalletAction.LoadWallet -> {
scope.launch {
store.state.globalState.tapWalletManager.loadWalletData()
}
}
is WalletAction.LoadPayId -> {
scope.launch {
store.state.globalState.tapWalletManager.loadPayId()
}
}
is WalletAction.LoadFiatRate -> {
scope.launch {
store.state.globalState.tapWalletManager.loadFiatRate(store.state.globalState.appCurrency)
}
}
is WalletAction.CreateWallet -> {
scope.launch {
val result = tangemSdkManager.createWallet(
store.state.globalState.scanNoteResponse?.card?.cardId
)
when (result) {
is CompletionResult.Success -> {
store.state.globalState.tapWalletManager.onCardScanned(result.data)
}
val walletMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
when (action) {
is WalletAction.TopUpAction -> topUpMiddleware.handle(action)
is WalletAction.LoadWallet -> {
scope.launch {
store.state.globalState.tapWalletManager.loadWalletData()
}
}
}
is WalletAction.UpdateWallet -> {
scope.launch { store.state.globalState.tapWalletManager.updateWallet() }
}
is WalletAction.UpdateWallet.Success -> setupWalletUpdate(action.wallet)
is WalletAction.LoadWallet.Success -> {
store.dispatch(WalletAction.CheckHashesCountOnline)
if (!store.state.walletState.updatingWallet) setupWalletUpdate(action.wallet)
}
is WalletAction.CreatePayId.CompleteCreatingPayId -> {
scope.launch {
val cardId = store.state.globalState.scanNoteResponse?.card?.cardId
val wallet = store.state.globalState.scanNoteResponse?.walletManager?.wallet
val publicKey = store.state.globalState.scanNoteResponse?.card?.cardPublicKey
if (cardId != null && wallet != null && publicKey != null) {
val result = PayIdManager().setPayId(
cardId, publicKey.toHexString(),
action.payId, wallet.address, wallet.blockchain
is WalletAction.LoadPayId -> {
scope.launch {
store.state.globalState.tapWalletManager.loadPayId()
}
}
is WalletAction.LoadFiatRate -> {
scope.launch {
store.state.globalState.tapWalletManager.loadFiatRate(store.state.globalState.appCurrency)
}
}
is WalletAction.CreateWallet -> {
scope.launch {
val result = tangemSdkManager.createWallet(
store.state.globalState.scanNoteResponse?.card?.cardId
)
withContext(Dispatchers.Main) {
when (result) {
is Result.Success ->
store.dispatch(WalletAction.CreatePayId.Success(action.payId))
is Result.Failure -> {
val error = result.error as? TapError
?: TapError.PayIdCreatingError
store.dispatch(WalletAction.CreatePayId.Failure(error))
when (result) {
is CompletionResult.Success -> {
store.state.globalState.tapWalletManager.onCardScanned(result.data)
}
}
}
}
is WalletAction.UpdateWallet -> {
scope.launch { store.state.globalState.tapWalletManager.updateWallet() }
}
is WalletAction.UpdateWallet.Success -> setupWalletUpdate(action.wallet)
is WalletAction.LoadWallet.Success -> {
store.dispatch(WalletAction.CheckHashesCountOnline)
if (!store.state.walletState.updatingWallet) setupWalletUpdate(action.wallet)
}
is WalletAction.CreatePayId.CompleteCreatingPayId -> {
scope.launch {
val cardId = store.state.globalState.scanNoteResponse?.card?.cardId
val wallet = store.state.globalState.scanNoteResponse?.walletManager?.wallet
val publicKey = store.state.globalState.scanNoteResponse?.card?.cardPublicKey
if (cardId != null && wallet != null && publicKey != null) {
val result = PayIdManager().setPayId(
cardId, publicKey.toHexString(),
action.payId, wallet.address, wallet.blockchain
)
withContext(Dispatchers.Main) {
when (result) {
is Result.Success ->
store.dispatch(WalletAction.CreatePayId.Success(action.payId))
is Result.Failure -> {
val error = result.error as? TapError
?: TapError.PayIdCreatingError
store.dispatch(WalletAction.CreatePayId.Failure(error))
}
}
}
}
}
}
}
is WalletAction.Scan -> {
scope.launch {
val result = tangemSdkManager.scanNote()
when (result) {
is CompletionResult.Success -> {
store.state.globalState.tapWalletManager.onCardScanned(result.data)
is WalletAction.Scan -> {
scope.launch {
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler)
when (result) {
is CompletionResult.Success -> {
store.state.globalState.tapWalletManager
.onCardScanned(result.data, true)
}
}
}
}
}
is WalletAction.LoadData -> {
scope.launch {
store.state.globalState.scanNoteResponse?.let {
store.state.globalState.tapWalletManager.loadData(it)
}
}
}
is NetworkStateChanged -> {
store.state.globalState.scanNoteResponse?.let { scanNoteResponse ->
store.dispatch(WalletAction.CheckHashesCountOnline)
is WalletAction.LoadData -> {
scope.launch {
store.state.globalState.tapWalletManager.onCardScanned(scanNoteResponse)
store.state.globalState.scanNoteResponse?.let {
store.state.globalState.tapWalletManager.loadData(it)
}
}
}
}
is WalletAction.CopyAddress -> {
store.state.walletState.addressData?.address?.let {
action.context.copyToClipboard(it)
store.dispatch(WalletAction.CopyAddress.Success)
is NetworkStateChanged -> {
store.state.globalState.scanNoteResponse?.let { scanNoteResponse ->
store.dispatch(WalletAction.CheckHashesCountOnline)
scope.launch {
store.state.globalState.tapWalletManager.onCardScanned(scanNoteResponse)
}
}
}
is WalletAction.CopyAddress -> {
store.state.walletState.addressData?.address?.let {
action.context.copyToClipboard(it)
store.dispatch(WalletAction.CopyAddress.Success)
}
}
is WalletAction.ExploreAddress -> {
val uri = Uri.parse(store.state.walletState.addressData?.exploreUrl)
val intent = Intent(Intent.ACTION_VIEW, uri)
ContextCompat.startActivity(action.context, intent, null)
}
is WalletAction.Send -> {
val newAction = prepareSendAction(action.amount)
store.dispatch(newAction)
if (newAction is PrepareSendScreen) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Send))
}
}
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))
}
}
is WalletAction.CheckHashesCountOnline -> checkHashesCountOnline()
is WalletAction.SaveCardId -> {
val cardId = store.state.globalState.scanNoteResponse?.card?.cardId
cardId?.let { preferencesStorage.saveScannedCardId(it) }
}
}
is WalletAction.ExploreAddress -> {
val uri = Uri.parse(store.state.walletState.addressData?.exploreUrl)
val intent = Intent(Intent.ACTION_VIEW, uri)
ContextCompat.startActivity(action.context, intent, null)
}
is WalletAction.Send -> {
val newAction = prepareSendAction(action.amount)
store.dispatch(newAction)
if (newAction is PrepareSendScreen) {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Send))
}
}
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))
}
}
is WalletAction.CheckHashesCountOnline -> checkHashesCountOnline()
is WalletAction.SaveCardId -> {
val cardId = store.state.globalState.scanNoteResponse?.card?.cardId
cardId?.let { preferencesStorage.saveScannedCardId(it) }
}
}
next(action)
}
}
}
private fun setupWalletUpdate(wallet: Wallet) {
if (!wallet.recentTransactions.toPendingTransactions(wallet.address).isNullOrEmpty()) {
store.dispatch(WalletAction.UpdateWallet.ScheduleUpdatingWallet)
scope.launch(Dispatchers.IO) {
delay(10000)
withContext(Dispatchers.Main) {
store.dispatch(WalletAction.UpdateWallet)
next(action)
}
}
}
}
private fun prepareSendAction(amount: Amount?): Action {
return if (amount != null) {
if (amount.type == AmountType.Token) {
PrepareSendScreen(store.state.walletState.wallet?.amounts?.get(AmountType.Coin), amount)
} else {
PrepareSendScreen(amount)
}
} else {
val amounts = store.state.walletState.wallet?.amounts?.toSendableAmounts()
if (amounts?.size ?: 0 > 1) {
WalletAction.Send.ChooseCurrency(amounts)
} else {
val amountToSend = amounts?.first()
PrepareSendScreen(amountToSend)
private fun setupWalletUpdate(wallet: Wallet) {
if (!wallet.recentTransactions.toPendingTransactions(wallet.address).isNullOrEmpty()) {
store.dispatch(WalletAction.UpdateWallet.ScheduleUpdatingWallet)
scope.launch(Dispatchers.IO) {
delay(10000)
withContext(Dispatchers.Main) {
store.dispatch(WalletAction.UpdateWallet)
}
}
}
}
}
private fun checkIfWarningNeeded(
card: Card, signatureCountValidator: SignatureCountValidator? = null
): WarningType? {
if (card.getType() != CardType.Release) {
return WarningType.DevCard
private fun prepareSendAction(amount: Amount?): Action {
return if (amount != null) {
if (amount.type == AmountType.Token) {
PrepareSendScreen(store.state.walletState.wallet?.amounts?.get(AmountType.Coin), amount)
} else {
PrepareSendScreen(amount)
}
} else {
val amounts = store.state.walletState.wallet?.amounts?.toSendableAmounts()
if (amounts?.size ?: 0 > 1) {
WalletAction.Send.ChooseCurrency(amounts)
} else {
val amountToSend = amounts?.first()
PrepareSendScreen(amountToSend)
}
}
}
return if (signatureCountValidator == null) {
if (card.walletSignedHashes ?: 0 > 0) {
WarningType.CardSignedHashesBefore
private fun checkIfWarningNeeded(
card: Card, signatureCountValidator: SignatureCountValidator? = null
): WarningType? {
if (card.getType() != CardType.Release) {
return WarningType.DevCard
}
return if (signatureCountValidator == null) {
if (card.walletSignedHashes ?: 0 > 0) {
WarningType.CardSignedHashesBefore
} else {
store.dispatch(WalletAction.SaveCardId)
null
}
} else {
store.dispatch(WalletAction.SaveCardId)
store.dispatch(WalletAction.NeedToCheckHashesCountOnline)
null
}
} else {
store.dispatch(WalletAction.NeedToCheckHashesCountOnline)
null
}
private fun checkHashesCountOnline() {
if (store.state.walletState.hashesCountVerified != false) return
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return
val card = store.state.globalState.scanNoteResponse?.card
if (card == null || preferencesStorage.wasCardScannedBefore(card.cardId)) return
val validator = store.state.globalState.scanNoteResponse?.walletManager
as? SignatureCountValidator
scope.launch {
val result = validator?.validateSignatureCount(card.walletSignedHashes ?: 0)
withContext(Dispatchers.Main) {
when (result) {
SimpleResult.Success -> {
store.dispatch(WalletAction.ConfirmHashesCount)
store.dispatch(WalletAction.SaveCardId)
}
is SimpleResult.Failure ->
if (result.error is BlockchainSdkError.SignatureCountNotMatched) {
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
} else if (card.walletSignedHashes ?: 0 > 0) {
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
}
}
}
}
}
}
private fun checkHashesCountOnline() {
if (store.state.walletState.hashesCountVerified != false) return
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return
private class TopUpMiddleware {
fun handle(action: WalletAction.TopUpAction) {
when (action) {
is WalletAction.TopUpAction.TopUp -> {
val url = TopUpHelper.getUrl(
store.state.walletState.currencyData.currencySymbol!!,
store.state.walletState.addressData!!.address
)
Timber.d(url)
store.dispatch(WalletAction.TopUpAction.Start(url, TopUpHelper.REDIRECT_URL))
store.dispatch(NavigationAction.NavigateTo(AppScreen.TopUp))
}
is WalletAction.TopUpAction.Start -> {
val card = store.state.globalState.scanNoteResponse?.card
if (card == null || preferencesStorage.wasCardScannedBefore(card.cardId)) return
val validator = store.state.globalState.scanNoteResponse?.walletManager
as? SignatureCountValidator
scope.launch {
val result = validator?.validateSignatureCount(card.walletSignedHashes ?: 0)
withContext(Dispatchers.Main) {
when (result) {
SimpleResult.Success -> {
store.dispatch(WalletAction.ConfirmHashesCount)
store.dispatch(WalletAction.SaveCardId)
}
is SimpleResult.Failure ->
if (result.error is BlockchainSdkError.SignatureCountNotMatched) {
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
} else if (card.walletSignedHashes ?: 0 > 0) {
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
}
}
is WalletAction.TopUpAction.Finish -> {
if (action.topUpCompleted) store.dispatch(WalletAction.UpdateWallet)
store.dispatch(NavigationAction.PopBackTo())
}
}
}

View file

@ -36,7 +36,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
is WalletAction.EmptyWallet -> newState = newState.copy(
state = ProgressState.Done,
currencyData = BalanceWidgetData(BalanceStatus.EmptyCard),
mainButton = WalletMainButton.CreateWalletButton(true)
mainButton = WalletMainButton.CreateWalletButton(true),
topUpState = TopUpState(false)
)
is WalletAction.LoadData.Failure -> {
when (action.error) {
@ -53,28 +54,27 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
addressData = addressData,
currencyData = BalanceWidgetData(
status = BalanceStatus.Unreachable,
currency = wallet?.blockchain?.fullName),
mainButton = WalletMainButton.SendButton(false)
currency = wallet?.blockchain?.fullName,
token = wallet?.token?.symbol?.let {
TokenData("", tokenSymbol = it)
}),
mainButton = WalletMainButton.SendButton(false),
topUpState = TopUpState(false)
)
}
is TapError.UnknownBlockchain -> {
newState = newState.copy(
state = ProgressState.Done,
currencyData = BalanceWidgetData(BalanceStatus.UnknownBlockchain)
currencyData = BalanceWidgetData(BalanceStatus.UnknownBlockchain),
topUpState = TopUpState(false)
)
}
}
}
is WalletAction.LoadWallet -> {
val wallet = state.globalState.scanNoteResponse?.walletManager?.wallet
val addressData = if (wallet == null) {
null
} else {
AddressData(wallet.address, wallet.shareUrl, wallet.exploreUrl)
}
val currentArtworkId = state.globalState.scanNoteResponse?.verifyResponse?.artworkInfo?.id
val cardImage = if (newState.cardImage?.artworkId == currentArtworkId) {
val wallet = action.wallet
val cardImage = if (newState.cardImage?.artworkId == action.artworkId) {
newState.cardImage
} else {
null
@ -84,11 +84,15 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
cardImage = cardImage,
currencyData = BalanceWidgetData(
BalanceStatus.Loading,
wallet?.blockchain?.fullName
wallet.blockchain.fullName,
currencySymbol = wallet.blockchain.currency,
token = wallet.token?.symbol?.let {
TokenData("", tokenSymbol = it)
}
),
addressData = addressData,
mainButton = WalletMainButton.SendButton(false)
addressData = AddressData(wallet.address, wallet.shareUrl, wallet.exploreUrl),
mainButton = WalletMainButton.SendButton(false),
topUpState = TopUpState(allowed = action.allowTopUp)
)
}
is WalletAction.LoadWallet.Success -> newState = onWalletLoaded(action.wallet, newState)
@ -109,7 +113,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
currencyData = newState.currencyData.copy(
status = BalanceStatus.Unreachable,
errorMessage = action.errorMessage
)
),
topUpState = TopUpState(false)
)
is WalletAction.UpdateWallet -> newState = newState.copy(updatingWallet = true)
is WalletAction.UpdateWallet.ScheduleUpdatingWallet ->
@ -204,11 +209,25 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
newState = newState.copy(hashesCountVerified = false)
is WalletAction.ConfirmHashesCount ->
newState = newState.copy(hashesCountVerified = true)
is WalletAction.TopUpAction -> {
newState = newState.copy(topUpState = handleTopUpActions(action, newState.topUpState))
}
}
return newState
}
private fun onWalletLoaded(wallet: Wallet, walletState: WalletState): WalletState {
private fun handleTopUpActions(action: WalletAction.TopUpAction, state: TopUpState): TopUpState {
return when (action) {
is WalletAction.TopUpAction.TopUp -> state
is WalletAction.TopUpAction.Start ->
state.copy(url = action.url, redirectUrl = action.redirectUrl)
is WalletAction.TopUpAction.Finish -> state.copy(url = null)
}
}
private fun onWalletLoaded(
wallet: Wallet, walletState: WalletState, topUpAllowed: Boolean? = null
): WalletState {
val fiatCurrencySymbol = store.state.globalState.appCurrency
val token = wallet.amounts[AmountType.Token]
val tokenData = if (token != null) {

View file

@ -21,7 +21,8 @@ data class WalletState(
val payIdData: PayIdData = PayIdData(),
val walletDialog: WalletDialog? = null,
val updatingWallet: Boolean = false,
val mainButton: WalletMainButton = WalletMainButton.SendButton(false)
val mainButton: WalletMainButton = WalletMainButton.SendButton(false),
val topUpState: TopUpState = TopUpState()
) : StateType {
val showDetails: Boolean =
currencyData.status != com.tangem.tap.features.wallet.ui.BalanceStatus.EmptyCard &&
@ -76,4 +77,10 @@ data class Artwork(
const val SERGIO_CARD_ID = "BC01"
const val MARTA_CARD_ID = "BC02"
}
}
}
data class TopUpState(
val allowed: Boolean = true,
val url: String? = null,
val redirectUrl: String? = null
)

View file

@ -8,7 +8,6 @@ import com.tangem.wallet.R
import kotlinx.android.synthetic.main.card_balance.*
import kotlinx.android.synthetic.main.layout_balance.*
import kotlinx.android.synthetic.main.layout_balance_error.*
import kotlinx.android.synthetic.main.layout_token.view.*
enum class BalanceStatus {
VerifiedOnline,
@ -50,20 +49,21 @@ class BalanceWidget(
fragment.l_balance.show()
fragment.l_balance_error.hide()
fragment.tv_fiat_amount.hide()
fragment.l_token.hide()
fragment.tv_currency.text = data.currency
fragment.tv_amount.text = ""
showStatus(R.id.tv_status_loading)
if (data.token != null) {
showBalanceWithToken(data, false)
} else {
showBalanceWithoutToken(data, false)
}
}
BalanceStatus.VerifiedOnline, BalanceStatus.TransactionInProgress -> {
fragment.l_balance.show()
fragment.l_balance_error.hide()
fragment.tv_currency.text = data.currency
fragment.tv_amount.text = data.amount
fragment.tv_fiat_amount.show()
fragment.tv_fiat_amount.text = data.fiatAmount
val statusView = if (data.status == BalanceStatus.VerifiedOnline) {
R.id.tv_status_verified
} else {
@ -75,22 +75,21 @@ class BalanceWidget(
fragment.tv_status_error_message.hide()
if (data.token != null) {
fragment.l_token.show()
fragment.l_token.tv_token_symbol.text = data.token.tokenSymbol
fragment.l_token.tv_token_amount.text = data.token.amount
fragment.l_token.tv_token_fiat_amount.text = data.token.fiatAmount
showBalanceWithToken(data, true)
} else {
fragment.l_token.hide()
showBalanceWithoutToken(data, true)
}
}
BalanceStatus.Unreachable -> {
fragment.l_balance.show()
fragment.l_balance_error.hide()
fragment.l_token.hide()
fragment.tv_fiat_amount.hide()
fragment.group_base_currency.hide()
fragment.tv_currency.text = data.currency
val currency = if (data.token != null) data.token.tokenSymbol else data.currency
fragment.tv_currency.text = currency
fragment.tv_amount.text = ""
fragment.tv_status_error_message.text = data.errorMessage
fragment.tv_status_error.text =
fragment.getString(R.string.wallet_balance_blockchain_unreachable)
@ -129,4 +128,26 @@ class BalanceWidget(
fragment.tv_status_loading.show(viewRes == R.id.tv_status_loading)
fragment.tv_status_verified.show(viewRes == R.id.tv_status_verified)
}
private fun showBalanceWithToken(data: BalanceWidgetData, showAmount: Boolean) {
fragment.group_base_currency.show()
fragment.tv_currency.text = data.token?.tokenSymbol
fragment.tv_base_currency.text = data.currency
fragment.tv_amount.text = if (showAmount) data.token?.amount else ""
fragment.tv_base_amount.text = if (showAmount) data.amount else ""
if (showAmount) {
fragment.tv_fiat_amount.show()
fragment.tv_fiat_amount.text = data.token?.fiatAmount
}
}
private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) {
fragment.group_base_currency.hide()
fragment.tv_currency.text = data.currency
fragment.tv_amount.text = if (showAmount) data.amount else ""
if (showAmount) {
fragment.tv_fiat_amount.show()
fragment.tv_fiat_amount.text = data.fiatAmount
}
}
}

View file

@ -29,6 +29,8 @@ import com.tangem.wallet.R
import kotlinx.android.synthetic.main.card_balance.*
import kotlinx.android.synthetic.main.fragment_wallet.*
import kotlinx.android.synthetic.main.layout_address.*
import kotlinx.android.synthetic.main.layout_wallet_long_buttons.*
import kotlinx.android.synthetic.main.layout_wallet_short_buttons.*
import org.rekotlin.StoreSubscriber
@ -39,7 +41,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
private lateinit var viewAdapter: PendingTransactionsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
@ -74,10 +75,6 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
}
btn_scan.setOnClickListener {
store.dispatch(WalletAction.Scan)
}
setupTransactionsRecyclerView()
}
@ -161,6 +158,29 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
}
private fun setupButtons(state: WalletState) {
if (state.topUpState.allowed) {
l_buttons_long.hide()
l_buttons_short.show()
} else {
l_buttons_long.show()
l_buttons_short.hide()
}
val btnConfirm = if (state.topUpState.allowed) {
btn_confirm_short
} else {
btn_confirm_long
}
val btnScan = if (state.topUpState.allowed) {
btn_scan_short
} else {
btn_scan_long
}
btnScan.setOnClickListener {
store.dispatch(WalletAction.Scan)
}
btn_copy.setOnClickListener { store.dispatch(WalletAction.CopyAddress(requireContext())) }
btn_show_qr.setOnClickListener { store.dispatch(WalletAction.ShowQrCode) }
@ -168,15 +188,20 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
is WalletMainButton.SendButton -> R.string.wallet_button_send
is WalletMainButton.CreateWalletButton -> R.string.wallet_button_create_wallet
}
btn_confirm.text = getString(buttonTitle)
btn_confirm.isEnabled = state.mainButton.enabled
btnConfirm.text = getString(buttonTitle)
btnConfirm.isEnabled = state.mainButton.enabled
btn_confirm.setOnClickListener {
btnConfirm.setOnClickListener {
when (state.mainButton) {
is WalletMainButton.SendButton -> store.dispatch(WalletAction.Send())
is WalletMainButton.CreateWalletButton -> store.dispatch(WalletAction.CreateWallet)
}
}
btn_top_up.setOnClickListener {
store.dispatch(
WalletAction.TopUpAction.TopUp(requireContext(), R.color.backgroundLightGray)
)
}
}
private fun setupAddressCard(state: WalletState) {

View file

@ -0,0 +1,63 @@
package com.tangem.tap.features.wallet.ui.topup
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fragment_topup.*
import org.rekotlin.StoreSubscriber
class TopUpFragment : Fragment(R.layout.fragment_topup), StoreSubscriber<WalletState> {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())
}
})
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
exitTransition = inflater.inflateTransition(R.transition.fade)
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.walletState == newState.walletState
}.select { it.walletState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
web_view.settings.javaScriptEnabled = true
toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
}
}
override fun newState(state: WalletState) {
if (activity == null) return
if (state.topUpState.url != null) {
web_view.webViewClient = TopUpWebViewClient(progress_bar, state.topUpState.redirectUrl)
web_view.loadUrl(state.topUpState.url)
}
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.tap.features.wallet.ui.topup
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.ProgressBar
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.extensions.show
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
class TopUpWebViewClient(
private val progressBar: ProgressBar, private val redirectUrl: String?
) : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
if (redirectUrl != null && url.contains(redirectUrl)) {
store.dispatch(WalletAction.TopUpAction.Finish(true))
return true
}
view.loadUrl(url)
return true
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
progressBar.hide()
}
init {
progressBar.show()
}
}

View file

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="10"
android:viewportHeight="12">
<group
android:scaleX="0.8"
android:pivotX="5.3"
android:pivotY="6"
android:rotation="180"
>
<path
android:pathData="M5.853,11.6645L9.7814,8.075C10.0495,7.8439 10.0734,7.3871 9.84,7.1191C9.6067,6.8511 9.1615,6.824 8.9084,7.0724L6.0712,9.6665L6.0712,0.8398C6.0712,0.468 5.7781,0.1667 5.4165,0.1667C5.0549,0.1667 4.7618,0.468 4.7618,0.8398L4.7618,9.6665L1.9246,7.0724C1.6715,6.824 1.2271,6.8576 0.9937,7.1256C0.7604,7.3936 0.7835,7.8439 1.0516,8.075L4.98,11.6645C5.2976,11.8989 5.5827,11.8802 5.853,11.6645L5.853,11.6645Z"
android:fillColor="#1C1C1E"
/>
</group>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="20">
<path
android:pathData="M11.4765,5.7026L6.7623,10.0101C6.4406,10.2874 6.412,10.8356 6.692,11.1572C6.972,11.4788 7.5063,11.5112 7.8099,11.2131L11.2146,8.1003L11.2146,18.6923C11.2146,19.1384 11.5664,19.5 12.0003,19.5C12.4342,19.5 12.7859,19.1384 12.7859,18.6923L12.7859,8.1003L16.1906,11.2131C16.4942,11.5112 17.0275,11.4709 17.3076,11.1493C17.5876,10.8277 17.5599,10.2874 17.2382,10.0101L12.524,5.7026C12.1429,5.4214 11.8008,5.4438 11.4765,5.7026L11.4765,5.7026Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="13dp"
android:height="16dp"
android:viewportWidth="13"
android:viewportHeight="18">
<path
android:pathData="M11.7908,6.0129C10.9896,3.7531 9.3666,1.9247 7.1993,0.8873C5.032,-0.1502 2.5873,-0.2837 0.3275,0.5175L0.2762,0.538C0.1734,0.5791 0.081,0.651 0.0399,0.764C-0.0114,0.8667 -0.0114,0.99 0.0296,1.0927C0.1221,1.329 0.3789,1.442 0.6254,1.3598C2.6695,0.6408 4.8676,0.764 6.809,1.6988C8.7606,2.6335 10.2295,4.277 10.9485,6.3108C11.2566,7.1839 11.4107,8.0878 11.4107,9.002C11.4107,9.9162 11.2566,10.8201 10.9485,11.6932C10.2295,13.7372 8.7606,15.3704 6.809,16.3052C4.8573,17.2399 2.6592,17.3632 0.6151,16.6441C0.3789,16.562 0.1221,16.6749 0.0296,16.9112C-0.0114,17.0242 -0.0114,17.1372 0.0399,17.2399C0.0913,17.3426 0.1734,17.4248 0.2864,17.4659L0.3378,17.4864C1.3136,17.8254 2.3202,18 3.3269,18C4.6519,18 5.977,17.7021 7.2096,17.1166C9.3769,16.0792 11.0101,14.2611 11.801,11.991C12.14,11.0255 12.3146,10.0189 12.3146,9.0122C12.3044,7.9851 12.1297,6.9784 11.7908,6.0129Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M1.1703,14.0252C1.1183,14.1498 1.1287,14.2848 1.1806,14.4095C1.2326,14.5341 1.3364,14.6172 1.4715,14.6588C2.0532,14.8457 2.6556,14.9392 3.2581,14.9392C3.9644,14.9392 4.6707,14.8146 5.3251,14.5549C6.7689,14.0044 7.9115,12.9137 8.5347,11.5011C8.8671,10.7532 9.0333,9.9742 9.0333,9.1744V9.0082C9.0126,8.2499 8.8464,7.502 8.5347,6.7957C7.9011,5.383 6.7689,4.3028 5.3251,3.7419C4.0787,3.2641 2.6972,3.2329 1.4299,3.6484C1.3157,3.6899 1.2118,3.773 1.1599,3.8873C1.1079,4.0016 1.1079,4.1262 1.1495,4.2405C1.2326,4.4586 1.4819,4.5729 1.7104,4.5001C2.7803,4.147 3.954,4.1677 5.0031,4.5729C6.2184,5.0403 7.1844,5.9543 7.7142,7.1489C7.9946,7.7721 8.1296,8.4265 8.14,9.1017V9.1328C8.14,9.8184 7.9946,10.4831 7.7142,11.1167C7.1844,12.3113 6.2184,13.2253 5.0031,13.6928C3.9436,14.0979 2.7699,14.1186 1.6896,13.7551C1.4819,13.7135 1.243,13.8174 1.1703,14.0252Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M3.9148,10.5778C3.6136,10.692 3.2812,10.7128 2.9592,10.6297C2.7619,10.5778 2.5438,10.6816 2.471,10.879V10.8894C2.4191,11.014 2.4295,11.1594 2.5022,11.2841C2.5645,11.4087 2.6892,11.5022 2.8346,11.5334C3.0112,11.5749 3.1774,11.5853 3.3539,11.5853C3.6552,11.5853 3.9564,11.5334 4.2472,11.4191C5.2028,11.0556 5.8469,10.1207 5.8469,9.0924C5.8469,8.0641 5.2028,7.1396 4.2472,6.7657C3.7694,6.5787 3.2501,6.5476 2.7411,6.6722C2.6268,6.7034 2.523,6.7761 2.471,6.8903C2.4191,6.9942 2.4087,7.1188 2.4503,7.2331L2.4606,7.2539C2.5438,7.472 2.7723,7.5862 3.0008,7.5447C3.302,7.472 3.624,7.4928 3.9148,7.607C4.5277,7.8356 4.9328,8.438 4.9328,9.0924C4.9328,9.7468 4.5277,10.3492 3.9148,10.5778Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -1,15 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="13dp"
android:height="18dp"
android:viewportWidth="13"
android:viewportHeight="18">
android:width="24dp"
android:height="21dp"
android:viewportWidth="24"
android:viewportHeight="21"
>
<path
android:pathData="M11.7908,6.0129C10.9896,3.7531 9.3666,1.9247 7.1993,0.8873C5.032,-0.1502 2.5873,-0.2837 0.3275,0.5175L0.2762,0.538C0.1734,0.5791 0.081,0.651 0.0399,0.764C-0.0114,0.8667 -0.0114,0.99 0.0296,1.0927C0.1221,1.329 0.3789,1.442 0.6254,1.3598C2.6695,0.6408 4.8676,0.764 6.809,1.6988C8.7606,2.6335 10.2295,4.277 10.9485,6.3108C11.2566,7.1839 11.4107,8.0878 11.4107,9.002C11.4107,9.9162 11.2566,10.8201 10.9485,11.6932C10.2295,13.7372 8.7606,15.3704 6.809,16.3052C4.8573,17.2399 2.6592,17.3632 0.6151,16.6441C0.3789,16.562 0.1221,16.6749 0.0296,16.9112C-0.0114,17.0242 -0.0114,17.1372 0.0399,17.2399C0.0913,17.3426 0.1734,17.4248 0.2864,17.4659L0.3378,17.4864C1.3136,17.8254 2.3202,18 3.3269,18C4.6519,18 5.977,17.7021 7.2096,17.1166C9.3769,16.0792 11.0101,14.2611 11.801,11.991C12.14,11.0255 12.3146,10.0189 12.3146,9.0122C12.3044,7.9851 12.1297,6.9784 11.7908,6.0129Z"
android:pathData="M17.7908,9.0129C16.9896,6.7531 15.3666,4.9247 13.1993,3.8873C11.032,2.8498 8.5873,2.7163 6.3275,3.5175L6.2762,3.538C6.1734,3.5791 6.081,3.651 6.0399,3.764C5.9886,3.8667 5.9886,3.99 6.0296,4.0927C6.1221,4.329 6.3789,4.442 6.6254,4.3598C8.6695,3.6408 10.8676,3.764 12.809,4.6988C14.7606,5.6335 16.2295,7.277 16.9485,9.3108C17.2566,10.1839 17.4107,11.0878 17.4107,12.002C17.4107,12.9161 17.2566,13.8201 16.9485,14.6932C16.2295,16.7372 14.7606,18.3704 12.809,19.3052C10.8574,20.2399 8.6592,20.3632 6.6151,19.6441C6.3789,19.562 6.1221,19.6749 6.0296,19.9112C5.9886,20.0242 5.9886,20.1372 6.0399,20.2399C6.0913,20.3426 6.1734,20.4248 6.2864,20.4659L6.3378,20.4864C7.3136,20.8254 8.3202,21 9.3269,21C10.6519,21 11.977,20.7021 13.2096,20.1166C15.3769,19.0792 17.0101,17.2611 17.801,14.991C18.14,14.0255 18.3146,13.0189 18.3146,12.0122C18.3044,10.9851 18.1297,9.9784 17.7908,9.0129Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M1.1703,14.0252C1.1183,14.1498 1.1287,14.2848 1.1806,14.4095C1.2326,14.5341 1.3364,14.6172 1.4715,14.6588C2.0532,14.8457 2.6556,14.9392 3.2581,14.9392C3.9644,14.9392 4.6707,14.8146 5.3251,14.5549C6.7689,14.0044 7.9115,12.9137 8.5347,11.5011C8.8671,10.7532 9.0333,9.9742 9.0333,9.1744V9.0082C9.0126,8.2499 8.8464,7.502 8.5347,6.7957C7.9011,5.383 6.7689,4.3028 5.3251,3.7419C4.0787,3.2641 2.6972,3.2329 1.4299,3.6484C1.3157,3.6899 1.2118,3.773 1.1599,3.8873C1.1079,4.0016 1.1079,4.1262 1.1495,4.2405C1.2326,4.4586 1.4819,4.5729 1.7104,4.5001C2.7803,4.147 3.954,4.1677 5.0031,4.5729C6.2184,5.0403 7.1844,5.9543 7.7142,7.1489C7.9946,7.7721 8.1296,8.4265 8.14,9.1017V9.1328C8.14,9.8184 7.9946,10.4831 7.7142,11.1167C7.1844,12.3113 6.2184,13.2253 5.0031,13.6928C3.9436,14.0979 2.7699,14.1186 1.6896,13.7551C1.4819,13.7135 1.243,13.8174 1.1703,14.0252Z"
android:pathData="M7.1702,17.0252C7.1183,17.1498 7.1287,17.2848 7.1806,17.4095C7.2326,17.5341 7.3365,17.6172 7.4715,17.6588C8.0532,17.8457 8.6556,17.9392 9.2581,17.9392C9.9644,17.9392 10.6707,17.8146 11.3251,17.5549C12.7689,17.0044 13.9115,15.9137 14.5347,14.5011C14.8671,13.7532 15.0333,12.9742 15.0333,12.1744V12.0082C15.0126,11.2499 14.8464,10.502 14.5347,9.7957C13.9011,8.383 12.7689,7.3028 11.3251,6.7419C10.0787,6.2641 8.6972,6.2329 7.4299,6.6484C7.3157,6.6899 7.2118,6.773 7.1599,6.8873C7.1079,7.0016 7.1079,7.1262 7.1495,7.2405C7.2326,7.4586 7.4819,7.5729 7.7104,7.5001C8.7803,7.147 9.954,7.1677 11.0031,7.5729C12.2184,8.0403 13.1844,8.9543 13.7142,10.1489C13.9946,10.7721 14.1296,11.4265 14.14,12.1017V12.1328C14.14,12.8184 13.9946,13.4831 13.7142,14.1167C13.1844,15.3113 12.2184,16.2253 11.0031,16.6928C9.9436,17.0979 8.7699,17.1186 7.6896,16.7551C7.4819,16.7135 7.243,16.8174 7.1702,17.0252Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M3.9148,10.5778C3.6136,10.692 3.2812,10.7128 2.9592,10.6297C2.7618,10.5778 2.5437,10.6816 2.471,10.879V10.8894C2.419,11.014 2.4294,11.1594 2.5021,11.2841C2.5645,11.4087 2.6891,11.5022 2.8345,11.5334C3.0111,11.5749 3.1773,11.5853 3.3539,11.5853C3.6551,11.5853 3.9563,11.5334 4.2472,11.4191C5.2028,11.0556 5.8468,10.1207 5.8468,9.0924C5.8468,8.0641 5.2028,7.1396 4.2472,6.7657C3.7694,6.5787 3.25,6.5476 2.741,6.6722C2.6268,6.7034 2.5229,6.7761 2.471,6.8903C2.419,6.9942 2.4086,7.1188 2.4502,7.2331L2.4606,7.2539C2.5437,7.472 2.7722,7.5862 3.0007,7.5447C3.3019,7.472 3.624,7.4928 3.9148,7.607C4.5276,7.8356 4.9327,8.438 4.9327,9.0924C4.9327,9.7468 4.5276,10.3492 3.9148,10.5778Z"
android:pathData="M9.9148,13.5778C9.6136,13.692 9.2812,13.7128 8.9592,13.6297C8.7619,13.5778 8.5437,13.6816 8.471,13.879V13.8894C8.4191,14.014 8.4295,14.1594 8.5022,14.2841C8.5645,14.4087 8.6892,14.5022 8.8346,14.5334C9.0112,14.5749 9.1774,14.5853 9.3539,14.5853C9.6552,14.5853 9.9564,14.5334 10.2472,14.4191C11.2029,14.0556 11.8469,13.1207 11.8469,12.0924C11.8469,11.0641 11.2029,10.1396 10.2472,9.7657C9.7694,9.5787 9.2501,9.5476 8.7411,9.6722C8.6268,9.7034 8.523,9.7761 8.471,9.8903C8.4191,9.9942 8.4087,10.1188 8.4503,10.2331L8.4607,10.2539C8.5437,10.472 8.7723,10.5863 9.0008,10.5447C9.302,10.472 9.624,10.4928 9.9148,10.607C10.5277,10.8356 10.9328,11.438 10.9328,12.0924C10.9328,12.7468 10.5277,13.3492 9.9148,13.5778Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector>
</selector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="19dp"
android:viewportWidth="24"
android:viewportHeight="19">
<path
android:pathData="M18.7974,10.9765L14.4899,6.2623C14.2126,5.9406 13.6644,5.912 13.3428,6.192C13.0212,6.472 12.9888,7.0063 13.2869,7.3099L16.3997,10.7146L5.8077,10.7146C5.3616,10.7146 5,11.0664 5,11.5003C5,11.9342 5.3616,12.2859 5.8077,12.2859L16.3997,12.2859L13.2869,15.6906C12.9888,15.9942 13.0291,16.5275 13.3507,16.8076C13.6723,17.0876 14.2126,17.0599 14.4899,16.7382L18.7974,12.024C19.0786,11.6429 19.0562,11.3008 18.7974,10.9765L18.7974,10.9765Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -63,7 +63,6 @@
android:id="@+id/btn_shop"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="33dp"
android:text="@string/common_no"
@ -85,7 +84,6 @@
android:id="@+id/btn_yes"
style="@style/TapButtonWithIcon"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="33dp"

View file

@ -104,7 +104,6 @@
android:id="@+id/btnSend"
style="@style/TapButtonWithIcon"
android:layout_width="match_parent"
android:layout_height="48dp"
android:fontFamily="@font/saira_semi_condensed_regular"
android:text="@string/send_title"
app:icon="@drawable/ic_arrow_right" />

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_close"
app:title="@string/wallet_button_topup" />
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
<ProgressBar
android:id="@+id/progress_bar"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminateOnly="true"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -49,7 +49,6 @@
android:id="@+id/iv_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="215dp"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
@ -57,6 +56,7 @@
android:layout_marginBottom="12dp"
android:adjustViewBounds="true"
android:elevation="3dp"
android:maxHeight="215dp"
android:scaleType="fitCenter"
android:src="@drawable/card_placeholder"
app:layout_constraintTop_toTopOf="parent" />
@ -85,47 +85,21 @@
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/l_card_balance" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_scan"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:text="@string/wallet_button_scan"
app:icon="@drawable/ic_scan"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/l_address"
app:layout_constraintVertical_bias="1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
<include
android:id="@+id/l_buttons_long"
layout="@layout/layout_wallet_long_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintGuide_percent="0.37" />
android:visibility="gone"/>
<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"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_confirm"
style="@style/TapButtonWithIcon"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:text="@string/wallet_button_send"
app:icon="@drawable/ic_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@id/l_address"
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -103,10 +103,10 @@
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="1sp"
app:autoSizeTextType="uniform"
app:layout_constraintBottom_toBottomOf="@id/tv_currency"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="@id/tv_currency"
app:layout_constraintBottom_toBottomOf="@id/tv_currency"
tools:text="0.43 BTC" />
<TextView
@ -130,22 +130,64 @@
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:textSize="14sp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_amount"
tools:text="USD 3 588"
android:visibility="invisible"/>
tools:text="USD 3 588" />
<include
android:id="@+id/l_token"
layout="@layout/layout_token"
<View
android:id="@+id/v_divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="16dp"
android:background="@color/lightGray5"
app:layout_constraintTop_toBottomOf="@id/tv_placeholder" />
<TextView
android:id="@+id/tv_base_currency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="35dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:textColor="@color/darkGray6"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_divider"
tools:text="Ethereum" />
<TextView
android:id="@+id/tv_base_amount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:ellipsize="end"
android:gravity="end"
android:maxLines="1"
android:textAlignment="textEnd"
android:textColor="@color/darkGray6"
android:textSize="14sp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/tv_currency" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/tv_base_currency"
app:layout_constraintTop_toBottomOf="@id/v_divider"
tools:text="0.00434143 ETH"
/>
<androidx.constraintlayout.widget.Group
android:id="@+id/group_base_currency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="v_divider, tv_base_currency, tv_base_amount" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_scan_long"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:text="@string/wallet_button_scan"
app:icon="@drawable/ic_scan"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintGuide_percent="0.37" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_confirm_long"
style="@style/TapButtonWithIcon"
android:layout_width="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:text="@string/wallet_button_send"
app:icon="@drawable/ic_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_scan_short"
style="@style/TapBlackButton"
android:layout_width="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:drawableTop="@drawable/ic_group_1243"
android:gravity="bottom|center_horizontal"
android:paddingTop="7dp"
android:text="@string/wallet_button_scan"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_top_up"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_top_up"
style="@style/TapButton"
android:layout_width="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:drawableTop="@drawable/ic_arrow_up_short_btn"
android:gravity="bottom|center_horizontal"
android:paddingTop="1dp"
android:text="@string/wallet_button_topup"
app:drawableTint="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_confirm_short"
app:layout_constraintStart_toEndOf="@+id/btn_scan_short"
app:layout_constraintVertical_bias="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_confirm_short"
style="@style/TapButton"
android:layout_width="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:drawableTop="@drawable/ic_send_short_btn"
android:gravity="bottom|center_horizontal"
android:paddingTop="2dp"
android:text="@string/wallet_button_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btn_top_up"
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -93,7 +93,7 @@
<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.\n 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">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_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>
@ -162,9 +162,35 @@ RECHTLICHER HAFTUNGSAUSSCHLUSS
<string name="disclaimer_title">Nutzungsbedingungen</string>
<string name="wallet_notification_no_internet">Keine Internetverbindung</string>
<string name="initial_message_scan_header">Tippen um zu scannen</string>
<string name="initial_message_tap_header">Tippen um zu scannen</string>
<string name="send_error_no_target_account">Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %1$s %2$s + Gebühr oder mehr sein</string>
<string name="send_error_fee_request_failed">Erhalt der Gebühr fehlgeschlagen</string>
<string name="send_error_unknown">Unbekannter Fehler</string>
<string name="send_error_payid_verification_failed">Verifikation der PayID ist fehlgeschlagen</string>
<string name="send_error_payid_unsupported_by_blockchain">PayID wird von der Blockchain nicht unterstützt</string>
<string name="send_error_payid_not_registered">PayID ist nicht registriert</string>
<string name="send_error_payid_request_failed">PayID-Anfrage ist fehlgeschlagen</string>
<string name="send_error_address_same_as_wallet">Die Adresse stimmt mit der Adresse Ihrer Brieftasche überein</string>
<string name="send_error_insufficient_balance">Nicht genug Geld</string>
<string name="send_error_blockchain_internal">Interner Fehler der Blockchain</string>
<string name="send_error_invalid_fee_value">Falsche Gebühr</string>
<string name="send_error_dust_amount_format">Minimaler Betrag ist %s</string>
<string name="send_error_dust_change">Restbestand zu klein</string>
<string name="wallet_notification_address_copied">Die Adresse wurde erfolgreich kopiert</string>
<string name="wallet_create_payid_empty">Zuerst geben Sie die gewünschte PayID ein</string>
<string name="initial_message_scan_header">Legen Sie die Karte zum Scannen an</string>
<string name="initial_message_tap_header">Legen Sie die Karte an</string>
<string name="details_notification_erase_wallet_not_possible">Ihr Kontostand in dieser Brieftasche ist nicht Null, oder Sie haben unbestätigte Transaktionen. Es ist unmöglich die Funktion der Brieftasche zu löschen.</string>
<string name="details_notification_security_option_already_active">Dies ist die derzeit aktive Wahl</string>
<string name="xtz_withdrawal_message_warning">Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden</string>
<string name="xtz_withdrawal_message_reduce">Um %s XTZ reduzieren</string>
<string name="xtz_withdrawal_message_ignore">Nein, alles senden</string>
</resources>

View file

@ -160,9 +160,29 @@ Avertissement
<string name="disclaimer_title"> Conditions d\'utilisation</string>
<string name="wallet_notification_no_internet">Pas de connexion internet</string>
<string name="initial_message_scan_header">Touchez pour scanner</string>
<string name="initial_message_tap_header">Touchez pour scanner</string>
<string name="send_error_no_target_account">Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %1$s %2$s + commissions ou plus</string>
<string name="send_error_fee_request_failed">Échec de réception des commissions</string>
<string name="send_error_unknown">Erreur inconnue</string>
<string name="send_error_payid_verification_failed">La vérification de PayID a échoué</string>
<string name="send_error_payid_unsupported_by_blockchain">PayID non pris en charge par la blockchain</string>
<string name="send_error_payid_not_registered">PayID non enregistré</string>
<string name="send_error_payid_request_failed">La demande de PayID a échoué</string>
<string name="send_error_address_same_as_wallet">Ladresse est la même que celle de votre portefeuille</string>
<string name="send_error_insufficient_balance">Solde insuffisant</string>
<string name="send_error_blockchain_internal">Erreur interne de la blockchain</string>
<string name="send_error_invalid_fee_value">Commission non valide</string>
<string name="send_error_dust_amount_format">Le montant minimal est de %ы</string>
<string name="send_error_dust_change">Le reste est trop petit</string>
<string name="wallet_notification_address_copied">Ladresse a été copiée avec succès</string>
<string name="wallet_create_payid_empty">Saisissez dabord le PayID requis</string>
<string name="initial_message_scan_header">Posez pour scanner</string>
<string name="initial_message_tap_header">Posez la carte</string>
<string name="details_notification_erase_wallet_not_possible">Votre solde sur ce portefeuille n\'est pas nul, ou vous avez des transactions non confirmées. Impossible de supprimer la fonction du portefeuille</string>
<string name="details_notification_security_option_already_active">Cette option est déjà active</string>
<string name="xtz_withdrawal_message_warning">Pour ne pas payer une commission élevée la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ</string>
<string name="xtz_withdrawal_message_reduce">Réduire de% s XTZ</string>
<string name="xtz_withdrawal_message_ignore">Non, envoyer toute la somme</string>
</resources>

View file

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="common_no">No</string>
<string name="common_save_changes">Mantieni le modifiche</string>
<string name="common_warning">Avviso</string>
<string name="common_retry">Riprova</string>
<string name="common_done">Fatto</string>
<string name="common_cancel">Annulla</string>
<string name="common_camera_denied_alert_title">Accesso alla videocamera negato</string>
<string name="common_camera_denied_alert_message">Non hai fornito l\'accesso alla tua videocamera, modifica le tue impostazioni sulla privacy</string>
<string name="common_camera_alert_button_settings">Impostazioni</string>
<string name="home_welcome">Benvenuti in Tangem. Hai una delle nostre schede?</string>>
<string name="home_welcome_back">Benevenuti di nuovo su Tangem Tap. Scansiona la tua scheda per iniziare.</string>
<string name="home_button_yes">Si! Scansiona scheda.</string>
<string name="home_button_shop">Shop</string>
<string name="home_ready_title">Preparati ad avvicinare la tua scheda sul retro del telefono.</string>
<string name="home_button_tapin">Avvicina</string>
<string name="home_button_scan">Scansiona scheda</string>
<string name="wallet_button_scan">Scansiona</string>
<string name="wallet_button_send">Invia</string>
<string name="wallet_button_create_wallet">Crea portafoglio</string>
<string name="wallet_title">Tangem Tap</string>
<string name="wallet_choice_wallet_option_title">Scegli l\'opzione del portafoglio</string>
<string name="wallet_balance_token_title">Token</string>
<string name="wallet_balance_tokens_title">Token</string>
<string name="wallet_balance_verified">Saldo verificato</string>
<string name="wallet_balance_loading">Il saldo sta per essere caricato…</string>
<string name="wallet_balance_blockchain_unreachable">Blockchain non raggiungibile</string>
<string name="wallet_error_no_account">Conto non creato</string>
<string name="wallet_error_no_account_subtitle_format">Carica %1$s+ %2$s per creare un conto</string>
<string name="wallet_error_empty_card">Scheda vuota</string>
<string name="wallet_error_empty_card_subtitle">Crea un portafoglio per iniziare ad utilizzare la tua scheda Tangem </string>
<string name="wallet_error_unsupported_blockchain">Questa scheda non è supportata</string>
<string name="wallet_error_unsupported_blockchain_subtitle"> La tua scheda Tangem è stata creata per funzionare con un\'altra applicazione. Leggere il nome e le istruzioni sulla scheda e installare l\'applicazione corretta</string>
<string name="wallet_balance_tx_in_progress">Transazione in corso&#8230;</string>
<string name="wallet_pending_tx_sending">Invia\u0020</string>
<string name="wallet_pending_tx_sending_address_format"> su %s </string>
<string name="wallet_pending_tx_receiving">Ricevi\u0020</string>
<string name="wallet_pending_tx_receiving_address_format"> da %s </string>
<string name="wallet_address_button_explore">Cerca indirizzo</string>
<string name="wallet_address_button_create_payid">Crea PayID</string>
<string name="wallet_qr_title_format">portafoglio $s</string>
<string name="wallet_create_payid">Crea PayID</string>
<string name="wallet_create_payid_card_format">Scheda: %s</string>
<string name="wallet_create_payid_hint">Nome PayID</string>
<string name="wallet_create_payid_domain">$payid.tangem.com</string>
<string name="wallet_create_payid_button_title">Crea</string>
<string name="wallet_create_payid_info">Il tuo PayID informazioni per te uniche, come il tuo numero di telefono, indirizzo email o ABN.</string>
<string name="wallet_create_payid_success_message">PayID creato con successo e copiato negli appunti</string>
<string name="wallet_create_payid_error_message">Errore di risposta durante la creazione del PayID</string>
<string name="wallet_create_payid_error_already_created">Questo PayID esiste già. Scegline un altro.</string>
<string name="send_destination_hint">Indirizzo o PayID</string>
<string name="send_title">Invia</string>
<string name="send_network_fee_title">Rete libera</string>
<string name="send_amount_label">Importo</string>
<string name="send_fee_label">Commissione</string>
<string name="send_total_label">Totale</string>
<string name="send_max_amount_label">Importo totale</string>
<string name="send_validation_invalid_address">Indirizzo non valido</string>
<string name="send_validation_invalid_amount">Importo non valido</string>
<string name="send_validation_invalid_total">Il totale supera il saldo</string>
<string name="send_validation_invalid_fee">La commissione supera il saldo </string>
<string name="send_fee_picker_low">Insufficiente</string>
<string name="send_fee_picker_normal">Normale</string>
<string name="send_fee_picker_priority">Prioritario</string>
<string name="send_fee_include_description">Includi commissione</string>
<string name="send_total_subtitle_format">Sarà inviato %1$s %2$s</string>
<string name="send_total_subtitle_fiat_format">≈ %1$s (inc. commissione: %2$s)</string>
<string name="send_total_subtitle_asset_format">Sarà inviato %1$s %2$s e %1$s %2$s</string>
<string name="send_balance_subtitle_format">Saldo: %1$s %2$s</string>
<string name="send_transaction_success">La transazione è stata firmata con successo e inviata al nodo blockchain. Il saldo del portafoglio verrà aggiornato dopo un po\' di tempo </string>
<string name="details_title">Requisiti</string>
<string name="details_row_title_cid">ID scheda</string>
<string name="details_row_title_issuer">Emittente</string>
<string name="details_row_title_signed_hashes">Firmato</string>
<string name="details_row_subtitle_signed_hashes_format">Hash %s</string>
<string name="details_row_title_currency">Valuta dell\'applicazione</string>
<string name="details_section_title_settings">Impostazioni</string>
<string name="details_section_title_card">Scheda</string>
<string name="details_row_title_validate">Convalidare la scheda</string>
<string name="details_row_title_manage_security">Gestione del portafoglio</string>
<string name="details_row_title_erase_wallet">Cancella il portafoglio</string>
<string name="details_erase_wallet_warning">Questa azione è irreversibile. Se dopo aver eliminato il portafoglio qualcuno invia dei fondi, non potrai ritirarli.</string>
<string name="details_security_management_warning">Se dimentichi il codice, perderai la possibilità di utilizzare la scheda. Non è possibile in alcun modo ripristinare o modificare il codice se lo perdi.</string>
<string name="details_manage_security_title">Gestione della sicurezza</string>
<string name="details_manage_security_long_tap">Mantenimento della scheda</string>
<string name="details_manage_security_long_tap_description">Questo meccanismo protegge dagli avvicinamenti senza contatto sulla scheda. Attiva un ritardo tra la ricezione e l\'esecuzione di un comando. Dopo la prima transazione firmata, questo telefono verrà associato alla scheda e le transazioni verranno firmate immediatamente.</string>
<string name="details_manage_security_passcode">Password</string>
<string name="details_manage_security_passcode_description">Dovrai inserire una password prima di eseguire qualsiasi comando che modifichi lo stato della scheda.</string>
<string name="details_manage_security_access_code">Codice di accesso</string>
<string name="details_manage_security_access_code_description">Prima di scansionare la scheda 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 scheda è già stata ricaricata e ha firmato transazioni in passato. Valuta la possibilità di prelevare immediatamente tutti i fondi se hai ricevuto questa scheda da una fonte inaffidabile.</string>
<string name="alert_unsupported_card">Questa scheda non è progettata per funzionare con Tangem Tap</string>
<string name="alert_developer_card">La scheda che hai scansionato è una scheda 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>
<string name="initial_message_sign_header">Avvicina per firmare</string>
<string name="initial_message_sign_body">Avvicina la scheda al telefono come mostrato sopra </string>
<string name="initial_message_purge_wallet_body">Avvicina per cancellare il portafoglio</string>
<string name="initial_message_create_wallet_body">Avvicina per creare il portafoglio</string>
<string name="initial_message_change_access_code_body">Avvicina per modificare il codice di accesso</string>
<string name="initial_message_change_passcode_body">Avvicina per modificare la password</string>
<string name="payid_service_error_loading">PayID non valido</string>
<string name="disclaimer_text">
NOTA LEGALE\n
\n
App Tangem Tap (software)\n
\n
1. Il software può essere utilizzato solo con i portafogli hardware Tangem (schede) tramite l\'interfaccia NFC. Il software NON esegue le seguenti operazioni:\n
\n
a) Generazione, archiviazione, trasferimento o accesso a chiavi crittografiche private (segrete) di portafogli blockchain contenenti risorse digitali, inclusa la criptovaluta.\n
\n
b) Generazione, archiviazione, trasferimento o accesso a chiavi segrete, password, passphrase, frasi di ripristino che possono essere utilizzate per recuperare o copiare chiavi private (segrete) su portafogli blockchain contenenti risorse digitali, inclusa la criptovaluta.\n
\n
c) Fornitura di servizi di scambio, negoziazione e investimento per conto di Tandem AG.\n
\n
2. Rischi associati al funzionamento del Software\n
\n
Tandem non sarà ritenuta responsabile per eventuali perdite, danni o reclami derivanti da eventi che rientrano nelle seguenti cinque categorie:\n
\n
a) Errori commessi dall\'utente di qualsiasi software o servizio relativo alla criptovaluta, ad esempio password dimenticate, pagamenti inviati a indirizzi errati e cancellazione accidentale di portafogli blockchain su Schede.\n
\n
b) Problemi con il software e/o qualsiasi software o servizio correlato a blockchain o criptovaluta, come file danneggiati, transazioni generate in modo improprio, librerie crittografiche non sicure, malware.\n
\n
c) Malfunzionamenti tecnici nell\'hardware dell\'utente, incluse le Schede, qualsiasi software o servizio relativo alla criptovaluta, ad esempio, perdita di dati a causa di un dispositivo di archiviazione difettoso o danneggiato.\n
\n
d) Problemi di sicurezza affrontati dall\'utente di qualsiasi software o servizio relativo alla criptovaluta, ad esempio l\'accesso non autorizzato a portafogli e/o account utente.\n
\n
e) Azioni o inattività di terze parti e/o eventi con cui si sono scontrate terze parti, come la bancarotta di fornitori di servizi, attacchi alla sicurezza delle informazioni relative ai fornitori di servizi e frodi perpetrate da terzi.\n
\n
3. Rischi commerciali e di investimento\n
\n
Qualsiasi transazione che coinvolge lo scambio di criptovalute o altre risorse digitali comporta rischi significativi. Qualsiasi transazione che include una valuta comporta dei rischi, inclusa ma non limitata alla possibilità di cambiamenti nelle condizioni economiche che potrebbero influenzare materialmente il valore o la liquidità della valuta. L\'investimento nella speculazione sui cambi di criptovaluta può anche essere soggetto a forti alti e bassi poiché i rispettivi prezzi di mercato fluttuano. È per questo motivo che è consigliabile utilizzare solo capitale di rischio quando si fanno affari in questi mercati.\n
\n
4. Rischi dell\'e-commerce\n
\n
Prima di effettuare transazioni utilizzando un sistema elettronico, è necessario leggere attentamente le norme e i regolamenti delle borse che offrono questo sistema e/o elencano i titoli che si intende negoziare. Il trading online presenta un rischio intrinseco dovuto alla risposta del sistema e ai tempi di accesso, che possono variare a seconda delle condizioni di mercato, delle prestazioni del sistema ed altri fattori. È necessario comprendere questi e altri rischi prima di fare trading.\n
\n
5. Rispetto degli obblighi fiscali\n
\n
Gli utenti del Software sono gli unici responsabili del determinare le eventuali tasse applicate alle loro transazioni in criptovaluta. I proprietari o i contributori del Software NON sono responsabili della determinazione delle tasse che si applicano alle transazioni in criptovaluta.\n
\n
6. Assenza di garanzie\n
\n
Il Software viene fornito &quot;così com\'è&quot; senza garanzia di alcun tipo riguardo al Software e/o a qualsiasi contenuto, dato, materiale e/o servizio fornito con il Software.\n
\n
7. Limitazione di responsabilità\n
\n
Salvo quanto diversamente previsto dalla legge, i proprietari o i contributori del Software non saranno in nessun caso responsabili per eventuali danni di qualsiasi tipo, inclusi, ma non limitati a, perdita di utilizzo, perdita di profitti o perdita di dati derivanti o in qualsiasi modo correlati all\'uso del Software. In nessun modo i proprietari o i contributori del Software sono responsabili delle azioni, decisioni o altri comportamenti presi o non presi da voi in relazione al Software.\n
\n
8. Ultima modifica\n
\n
Questa nota legale è stata modificata l\'ultima volta 01.10.2020.
</string>
<string name="send_error_no_target_account">Per creare un account, invia %1$s %2$s a questo indirizzo</string>
<string name="send_error_fee_request_failed">Impossibile ottenere la commissione</string>
<string name="common_accept">Accetta</string>
<string name="send_validation_amount_exceeds_balance">Amount Exceeds Balance</string>
<string name="disclaimer_title">Termini del servizio</string>
<string name="wallet_notification_no_internet">Nessuna connessione a Internet</string>
<string name="send_error_unknown">Errore sconosciuto</string>
<string name="send_error_payid_verification_failed">Verifica del PayID fallita</string>
<string name="send_error_payid_unsupported_by_blockchain">PayID non supportato dalla blockchain</string>
<string name="send_error_payid_not_registered">PayID non registrato</string>
<string name="send_error_payid_request_failed">Richiesta PayID fallita</string>
<string name="send_error_address_same_as_wallet">L\'indirizzo corrisponde all\'indirizzo del tuo portafoglio</string>
<string name="send_error_insufficient_balance">Saldo insufficiente</string>
<string name="send_error_blockchain_internal">Errore interno della blockchain</string>
<string name="send_error_invalid_fee_value">Commissione non valida</string>
<string name="send_error_dust_amount_format">L\'importo minimo è di %s</string>
<string name="send_error_dust_change">L\'importo residuo è molto basso</string>
<string name="wallet_notification_address_copied">L\'indirizzo è stato copiato con successo</string>
<string name="wallet_create_payid_empty">Inserire prima il PayID desiderato</string>
<string name="initial_message_scan_header">Avvicina per scansionare</string>
<string name="initial_message_tap_header">Avvicina la scheda</string>
<string name="details_notification_erase_wallet_not_possible">Il tuo saldo su questo portafoglio non è pari a zero o hai transazioni non confermate. Non è possibile eliminare la funzione portafoglio.</string>
<string name="details_notification_security_option_already_active">E\' l\'opzione attualmente attiva</string>
<string name="xtz_withdrawal_message_warning">Per evitare di pagare una commissione maggiore la prossima volta che ricarichi il tuo portafoglio, riduci l\'importo di %s XTZ</string>
<string name="xtz_withdrawal_message_reduce">Riduci di %s XTZ</string>
<string name="xtz_withdrawal_message_ignore">No, invia l\'intero importo</string>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:forceDarkAllowed">false</item>
</style>
</resources>

View file

@ -50,7 +50,7 @@
<string name="wallet_address_button_explore">Explore address</string>
<string name="wallet_address_button_create_payid">Create PayID</string>
<string name="wallet_qr_title_format">$s wallet</string>
<string name="wallet_qr_title_format">%s wallet</string>
<string name="wallet_create_payid">Create PayID</string>
<string name="wallet_create_payid_card_format">Card: %s</string>
@ -106,7 +106,7 @@
<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.\n\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020Consider immediate withdrawal of all funds if you have received this card from an untrusted source.</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_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. Dont accept it as a payment</string>
<string name="alert_old_card">Tangem cards manufactured before September 2019 cannot currently be extracted with an iPhone. Were working hard with Apple to make it possible in future versions of iOS.</string>
@ -200,4 +200,11 @@
<string name="details_notification_security_option_already_active">This is the currently active option</string>
<string name="xtz_withdrawal_message_warning">To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ</string>
<string name="xtz_withdrawal_message_reduce">Reduce by %s XTZ</string>
<string name="xtz_withdrawal_message_ignore">No, send all</string>
</resources>

View file

@ -1,7 +1,3 @@
<resources>
<string name="xtz_withdrawal_message_warning" translatable="false">To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ</string>
<string name="xtz_withdrawal_message_reduce" translatable="false">Reduce by %s XTZ</string>
<string name="xtz_withdrawal_message_ignore" translatable="false">No, send all</string>
<string name="wallet_button_topup" translatable="false">Top Up</string>
</resources>

View file

@ -1,6 +1,6 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<style name="BaseAppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorSecondary">@color/colorSecondary</item>
@ -10,6 +10,8 @@
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
</style>
<style name="AppTheme" parent="BaseAppTheme" />
<!-- Toolbar -->
<style name="DarkToolbarStyle" parent="Theme.AppCompat">
<item name="android:textColorPrimary">@android:color/white</item>
@ -34,7 +36,7 @@
<item name="cornerRadius">@dimen/btn_corner_radius</item>
<item name="android:fontFamily">@font/saira_semi_condensed_regular</item>
<item name="android:layout_width">93dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:layout_height">52dp</item>
<item name="elevation">3dp</item>
</style>