diff --git a/app/build.gradle b/app/build.gradle index a54de48953..de5564ec62 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0def014c91..2b7b764bfc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ + diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index ffa1f2aa54..d8e89fe868 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -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(NfcAdapter.EXTRA_TAG) if (tag != null) { intent.action = null + store.dispatch(NavigationAction.NavigateTo(AppScreen.Home, false)) store.dispatch(HomeAction.ReadCard) } } diff --git a/app/src/main/java/com/tangem/tap/TapConfig.kt b/app/src/main/java/com/tangem/tap/TapConfig.kt index 483f9e8306..db4767cd0e 100644 --- a/app/src/main/java/com/tangem/tap/TapConfig.kt +++ b/app/src/main/java/com/tangem/tap/TapConfig.kt @@ -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" } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEvent.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEvent.kt new file mode 100644 index 0000000000..932897e204 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEvent.kt @@ -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"), +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandler.kt new file mode 100644 index 0000000000..8057bcae9e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandler.kt @@ -0,0 +1,7 @@ +package com.tangem.tap.common.analytics + +import com.tangem.commands.Card + +interface AnalyticsHandler { + fun triggerEvent(event: AnalyticsEvent, card: Card?) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt new file mode 100644 index 0000000000..6e7f460773 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt @@ -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"), + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index bb69887342..588342e8f7 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -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() diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index d300bb65b7..e60ae97fa7 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -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> { return listOf( logMiddleware, navigationMiddleware, notificationsMiddleware, globalMiddleware, - homeMiddleware, walletMiddleware, sendMiddleware, + HomeMiddleware().homeMiddleware, + WalletMiddleware().walletMiddleware, + sendMiddleware, DetailsMiddleware().detailsMiddleware, DisclaimerMiddleware().disclaimerMiddleware ) diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt index 5edfad540b..33d2b18a16 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt @@ -9,4 +9,4 @@ data class NavigationState( val activity: WeakReference? = null ) : StateType -enum class AppScreen { Home, Wallet, Send, Details, DetailsConfirm, DetailsSecurity, Disclaimer } \ No newline at end of file +enum class AppScreen { Home, Wallet, TopUp, Send, Details, DetailsConfirm, DetailsSecurity, Disclaimer } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index d6b7730bcb..a1971bad03 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -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 { + suspend fun scanNote(analyticsHandler: AnalyticsHandler): CompletionResult { + analyticsHandler.triggerEvent(AnalyticsEvent.READY_TO_SCAN, null) return runTaskAsyncReturnOnMain(ScanNoteTask(), initialMessage = Message(activity.getString(R.string.initial_message_scan_header))) } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index cea0ea99b2..7334aecc0d 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -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)) } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt index 7764650537..b0bedc66be 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt @@ -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 } diff --git a/app/src/main/java/com/tangem/tap/domain/TopUpHelper.kt b/app/src/main/java/com/tangem/tap/domain/TopUpHelper.kt new file mode 100644 index 0000000000..6f715de06b --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/TopUpHelper.kt @@ -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 = "¤cyCode=" + 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())) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index b67c254be3..987e3c1b3b 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -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 = { 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 = { 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" + + diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 03e3ba943c..34414e9381 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -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) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index 1a573776e6..5ac957f1f4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -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() + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt index 125d22f468..71d07e315d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt @@ -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 = { 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 = { 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()) } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt index 326d692604..358fe8cffc 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt @@ -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) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index be5c2fad71..d6c916d79e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -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" } -} \ No newline at end of file +} + +data class TopUpState( + val allowed: Boolean = true, + val url: String? = null, + val redirectUrl: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt index 65c7679e62..cc65bff46d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt @@ -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 + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index c3e7f6c8fe..25f00a2e49 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -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 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) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/topup/TopUpFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/topup/TopUpFragment.kt new file mode 100644 index 0000000000..20a844418f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/topup/TopUpFragment.kt @@ -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 { + + 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) + } + } + +} diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/topup/TopUpWebViewClient.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/topup/TopUpWebViewClient.kt new file mode 100644 index 0000000000..d728b16128 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/topup/TopUpWebViewClient.kt @@ -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() + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_up.xml b/app/src/main/res/drawable/ic_arrow_up.xml new file mode 100644 index 0000000000..34f1d028fe --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_up.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_arrow_up_short_btn.xml b/app/src/main/res/drawable/ic_arrow_up_short_btn.xml new file mode 100644 index 0000000000..b739da9ccb --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_up_short_btn.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml new file mode 100644 index 0000000000..16d6d37dd9 --- /dev/null +++ b/app/src/main/res/drawable/ic_close.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_group_1243.xml b/app/src/main/res/drawable/ic_group_1243.xml new file mode 100644 index 0000000000..c1e2907eb0 --- /dev/null +++ b/app/src/main/res/drawable/ic_group_1243.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_scan.xml b/app/src/main/res/drawable/ic_scan.xml index 7fcb008d1d..476424f743 100644 --- a/app/src/main/res/drawable/ic_scan.xml +++ b/app/src/main/res/drawable/ic_scan.xml @@ -1,15 +1,16 @@ + android:width="24dp" + android:height="21dp" + android:viewportWidth="24" + android:viewportHeight="21" + > diff --git a/app/src/main/res/drawable/ic_scan_for_short_btn.xml b/app/src/main/res/drawable/ic_scan_for_short_btn.xml new file mode 100644 index 0000000000..1c281ecd9c --- /dev/null +++ b/app/src/main/res/drawable/ic_scan_for_short_btn.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_send_short_btn.xml b/app/src/main/res/drawable/ic_send_short_btn.xml new file mode 100644 index 0000000000..273ed56f76 --- /dev/null +++ b/app/src/main/res/drawable/ic_send_short_btn.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 5bff544835..33157a5fe6 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -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" diff --git a/app/src/main/res/layout/fragment_send.xml b/app/src/main/res/layout/fragment_send.xml index 35b5a31030..fca84784bc 100644 --- a/app/src/main/res/layout/fragment_send.xml +++ b/app/src/main/res/layout/fragment_send.xml @@ -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" /> diff --git a/app/src/main/res/layout/fragment_topup.xml b/app/src/main/res/layout/fragment_topup.xml new file mode 100644 index 0000000000..8069c307f0 --- /dev/null +++ b/app/src/main/res/layout/fragment_topup.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index b09f9cb769..1f139adb02 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -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" /> - - - - + android:visibility="gone"/> + + - diff --git a/app/src/main/res/layout/layout_balance.xml b/app/src/main/res/layout/layout_balance.xml index de3660b802..b4ac0497dd 100644 --- a/app/src/main/res/layout/layout_balance.xml +++ b/app/src/main/res/layout/layout_balance.xml @@ -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" /> + tools:text="USD 3 588" /> - + + + + + 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" + /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_wallet_long_buttons.xml b/app/src/main/res/layout/layout_wallet_long_buttons.xml new file mode 100644 index 0000000000..3872698afc --- /dev/null +++ b/app/src/main/res/layout/layout_wallet_long_buttons.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_wallet_short_buttons.xml b/app/src/main/res/layout/layout_wallet_short_buttons.xml new file mode 100644 index 0000000000..4971b42309 --- /dev/null +++ b/app/src/main/res/layout/layout_wallet_short_buttons.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0675f2dd48..467c665f4f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -93,7 +93,7 @@ Zugangscode Sie müssen den richtigen Zugangscode eingeben, bevor Sie die Karte scannen. Sie können NFC-Probleme mit einigen iPhone 7/7+ während der Extraktion haben - 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. + 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. Diese Karte ist für die Zusammenarbeit mit Tangem Tap nicht geeignet Die von Ihnen gescannte Karte ist eine Entwicklungskarte. Akzeptieren Sie sie nicht als Zahlungsmittel @@ -162,9 +162,35 @@ RECHTLICHER HAFTUNGSAUSSCHLUSS Nutzungsbedingungen Keine Internetverbindung - Tippen um zu scannen - Tippen um zu scannen Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %1$s %2$s + Gebühr oder mehr sein Erhalt der Gebühr fehlgeschlagen + Unbekannter Fehler + Verifikation der PayID ist fehlgeschlagen + PayID wird von der Blockchain nicht unterstützt + PayID ist nicht registriert + PayID-Anfrage ist fehlgeschlagen + + Die Adresse stimmt mit der Adresse Ihrer Brieftasche überein + Nicht genug Geld + Interner Fehler der Blockchain + Falsche Gebühr + Minimaler Betrag ist %s + Restbestand zu klein + + Die Adresse wurde erfolgreich kopiert + + + Zuerst geben Sie die gewünschte PayID ein + + Legen Sie die Karte zum Scannen an + Legen Sie die Karte an + + 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. + Dies ist die derzeit aktive Wahl + + Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden + Um %s XTZ reduzieren + Nein, alles senden + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4bf21924ff..f315ba278d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -160,9 +160,29 @@ Avertissement Conditions d\'utilisation Pas de connexion internet - Touchez pour scanner - Touchez pour scanner Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %1$s %2$s + commissions ou plus Échec de réception des commissions + Erreur inconnue + La vérification de PayID a échoué + PayID non pris en charge par la blockchain + PayID non enregistré + La demande de PayID a échoué + L’adresse est la même que celle de votre portefeuille + Solde insuffisant + Erreur interne de la blockchain + Commission non valide + Le montant minimal est de %ы + Le reste est trop petit + L’adresse a été copiée avec succès + Saisissez d’abord le PayID requis + Posez pour scanner + Posez la carte + Votre solde sur ce portefeuille n\'est pas nul, ou vous avez des transactions non confirmées. Impossible de supprimer la fonction du portefeuille + Cette option est déjà active + + Pour ne pas payer une commission élevée la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ + Réduire de% s XTZ + Non, envoyer toute la somme + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml new file mode 100644 index 0000000000..93bac3c897 --- /dev/null +++ b/app/src/main/res/values-it/strings.xml @@ -0,0 +1,195 @@ + + + + No + Mantieni le modifiche + Avviso + Riprova + Fatto + Annulla + Accesso alla videocamera negato + Non hai fornito l\'accesso alla tua videocamera, modifica le tue impostazioni sulla privacy + Impostazioni + Benvenuti in Tangem. Hai una delle nostre schede?> + Benevenuti di nuovo su Tangem Tap. Scansiona la tua scheda per iniziare. + Si! Scansiona scheda. + Shop + Preparati ad avvicinare la tua scheda sul retro del telefono. + Avvicina + Scansiona scheda + Scansiona + Invia + Crea portafoglio + Tangem Tap + Scegli l\'opzione del portafoglio + Token + Token + Saldo verificato + Il saldo sta per essere caricato… + Blockchain non raggiungibile + Conto non creato + Carica %1$s+ %2$s per creare un conto + Scheda vuota + Crea un portafoglio per iniziare ad utilizzare la tua scheda Tangem + Questa scheda non è supportata + 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 + Transazione in corso… + Invia\u0020 + su %s + Ricevi\u0020 + da %s + Cerca indirizzo + Crea PayID + portafoglio $s + Crea PayID + Scheda: %s + Nome PayID + $payid.tangem.com + Crea + Il tuo PayID – informazioni per te uniche, come il tuo numero di telefono, indirizzo email o ABN. + PayID creato con successo e copiato negli appunti + Errore di risposta durante la creazione del PayID + Questo PayID esiste già. Scegline un altro. + Indirizzo o PayID + Invia + Rete libera + Importo + Commissione + Totale + Importo totale + Indirizzo non valido + Importo non valido + Il totale supera il saldo + La commissione supera il saldo + Insufficiente + Normale + Prioritario + Includi commissione + Sarà inviato %1$s %2$s + ≈ %1$s (inc. commissione: %2$s) + Sarà inviato %1$s %2$s e %1$s %2$s + Saldo: %1$s %2$s + La transazione è stata firmata con successo e inviata al nodo blockchain. Il saldo del portafoglio verrà aggiornato dopo un po\' di tempo + Requisiti + ID scheda + Emittente + Firmato + Hash %s + Valuta dell\'applicazione + Impostazioni + Scheda + Convalidare la scheda + Gestione del portafoglio + Cancella il portafoglio + Questa azione è irreversibile. Se dopo aver eliminato il portafoglio qualcuno invia dei fondi, non potrai ritirarli. + Se dimentichi il codice, perderai la possibilità di utilizzare la scheda. Non è possibile in alcun modo ripristinare o modificare il codice se lo perdi. + Gestione della sicurezza + Mantenimento della scheda + 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. + Password + Dovrai inserire una password prima di eseguire qualsiasi comando che modifichi lo stato della scheda. + Codice di accesso + Prima di scansionare la scheda sarà necessario inserire il codice di accesso corretto + Potresti riscontrare problemi con l\'NFC su alcuni iPhone 7/7 + durante la rimozione + 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. + Questa scheda non è progettata per funzionare con Tangem Tap + La scheda che hai scansionato è una scheda di sviluppo. Non utilizzarla come strumento di pagamento + 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. + Avvicina per firmare + Avvicina la scheda al telefono come mostrato sopra + Avvicina per cancellare il portafoglio + Avvicina per creare il portafoglio + Avvicina per modificare il codice di accesso + Avvicina per modificare la password + PayID non valido + + + + 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 "così com\'è" 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. + + + + Per creare un account, invia %1$s %2$s a questo indirizzo + Impossibile ottenere la commissione + Accetta + Amount Exceeds Balance + Termini del servizio + Nessuna connessione a Internet + + Errore sconosciuto + Verifica del PayID fallita + PayID non supportato dalla blockchain + PayID non registrato + Richiesta PayID fallita + + L\'indirizzo corrisponde all\'indirizzo del tuo portafoglio + Saldo insufficiente + Errore interno della blockchain + Commissione non valida + L\'importo minimo è di %s + L\'importo residuo è molto basso + + L\'indirizzo è stato copiato con successo + + + Inserire prima il PayID desiderato + + Avvicina per scansionare + Avvicina la scheda + + Il tuo saldo su questo portafoglio non è pari a zero o hai transazioni non confermate. Non è possibile eliminare la funzione portafoglio. + E\' l\'opzione attualmente attiva + + Per evitare di pagare una commissione maggiore la prossima volta che ricarichi il tuo portafoglio, riduci l\'importo di %s XTZ + Riduci di %s XTZ + No, invia l\'intero importo + + \ No newline at end of file diff --git a/app/src/main/res/values-v29/styles.xml b/app/src/main/res/values-v29/styles.xml new file mode 100644 index 0000000000..7032bb8f84 --- /dev/null +++ b/app/src/main/res/values-v29/styles.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9af2597610..a14f49d345 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,7 +50,7 @@ Explore address Create PayID - $s wallet + %s wallet Create PayID Card: %s @@ -106,7 +106,7 @@ You will have to submit the correct access code before scanning the card You may experience NFC problems with some iPhone 7/7+ during the extraction - 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. + 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. This card it is not designed to work with Tangem Tap The card you scanned is a development card. Don’t accept it as a payment 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. @@ -200,4 +200,11 @@ This is the currently active option + To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ + Reduce by %s XTZ + No, send all + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index ee920115aa..834037ecad 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -1,7 +1,3 @@ - - To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ - Reduce by %s XTZ - No, send all - + Top Up diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 61530d2290..5c6ee06378 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,6 +1,6 @@ - +