Updated on 2026-08-14
|
|
@ -38,7 +38,7 @@ android {
|
|||
}
|
||||
debug_beta {
|
||||
initWith release
|
||||
debuggable false
|
||||
debuggable true
|
||||
versionNameSuffix "-beta"
|
||||
applicationIdSuffix ".debug"
|
||||
buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"prod\"'
|
||||
|
|
@ -78,8 +78,8 @@ dependencies {
|
|||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation 'com.tangem:blockchain:develop-64'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-131'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-131'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-132'
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:android:develop-132'
|
||||
|
||||
// WebView
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
|
|
@ -129,6 +129,15 @@ dependencies {
|
|||
// animation
|
||||
implementation "com.airbnb.android:lottie:3.4.0"
|
||||
|
||||
// Shopify
|
||||
implementation('com.shopify.mobilebuysdk:buy3:12.0.0') {
|
||||
exclude group: "com.shopify.graphql.support"
|
||||
exclude module: 'joda-time'
|
||||
}
|
||||
|
||||
// Google Pay
|
||||
implementation 'com.google.android.gms:play-services-wallet:19.1.0'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation "com.google.truth:truth:1.1.3"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@
|
|||
tools:ignore="GoogleAppIndexingWarning"
|
||||
tools:replace="android:fullBackupContent">
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.wallet.api.enabled"
|
||||
android:value="true" />
|
||||
|
||||
<activity
|
||||
android:name="com.tangem.tap.MainActivity"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 42803296690ad6914ec2c59c5fdc3f0fb30f8afc
|
||||
Subproject commit 180252680e80b88f8fec9add783207d41d30e4e3
|
||||
|
|
@ -18,8 +18,12 @@ import com.tangem.tap.common.redux.global.AndroidResources
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.common.shop.GooglePayService
|
||||
import com.tangem.tap.common.shop.GooglePayService.Companion.LOAD_PAYMENT_DATA_REQUEST_CODE
|
||||
import com.tangem.tap.common.shop.googlepay.GooglePayUtil.createPaymentsClient
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.shop.redux.ShopAction
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
|
|
@ -73,8 +77,14 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
|
||||
store.dispatch(GlobalAction.SetResources(getAndroidResources()))
|
||||
store.dispatch(WalletConnectAction.RestoreSessions)
|
||||
store.dispatch(
|
||||
ShopAction.CheckIfGooglePayAvailable(
|
||||
GooglePayService(createPaymentsClient(this), this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun getAndroidResources(): AndroidResources {
|
||||
return AndroidResources(
|
||||
AndroidResources.RString(
|
||||
|
|
@ -97,7 +107,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
||||
val isScannedBefore = store.state.globalState.scanResponse != null
|
||||
val isOnboardingServiceActive = store.state.globalState.onboardingState.onboardingStarted
|
||||
if (backStackIsEmpty || (!isOnboardingServiceActive && !isScannedBefore)) {
|
||||
val shopOpened = store.state.shopState.total != null
|
||||
if (backStackIsEmpty || (!isOnboardingServiceActive && !isScannedBefore && !shopOpened)) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
|
||||
}
|
||||
intentHandler.handleIntent(intent)
|
||||
|
|
@ -140,4 +151,15 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
snackbar?.dismiss()
|
||||
snackbar = null
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when (requestCode) {
|
||||
LOAD_PAYMENT_DATA_REQUEST_CODE -> {
|
||||
store.dispatch(
|
||||
ShopAction.BuyWithGooglePay.HandleGooglePayResponse(resultCode, data)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import com.tangem.tap.common.images.PicassoHelper
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.appReducer
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.shop.TangemShopService
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.config.FeaturesLocalLoader
|
||||
import com.tangem.tap.domain.configurable.config.FeaturesRemoteLoader
|
||||
|
|
@ -37,6 +38,7 @@ val store = Store(
|
|||
lateinit var preferencesStorage: PreferencesStorage
|
||||
lateinit var currenciesRepository: CurrenciesRepository
|
||||
lateinit var walletConnectRepository: WalletConnectRepository
|
||||
lateinit var shopService: TangemShopService
|
||||
|
||||
class TapApplication : Application() {
|
||||
override fun onCreate() {
|
||||
|
|
@ -72,7 +74,10 @@ class TapApplication : Application() {
|
|||
val localLoader = FeaturesLocalLoader(this, moshi)
|
||||
val remoteLoader = FeaturesRemoteLoader(moshi)
|
||||
val configManager = ConfigManager(localLoader, remoteLoader)
|
||||
configManager.load { store.dispatch(GlobalAction.SetConfigManager(configManager)) }
|
||||
configManager.load {
|
||||
store.dispatch(GlobalAction.SetConfigManager(configManager))
|
||||
shopService = TangemShopService(this, configManager.config.shopify!!)
|
||||
}
|
||||
val warningsManager = WarningMessagesManager(RemoteWarningLoader(moshi))
|
||||
warningsManager.load { store.dispatch(GlobalAction.SetWarningManager(warningsManager)) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.tangem.tap.features.onboarding.products.otherCards.OnboardingOtherCar
|
|||
import com.tangem.tap.features.onboarding.products.twins.ui.TwinsCardsFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFragment
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.shop.ui.ShopFragment
|
||||
import com.tangem.tap.features.tokens.ui.AddTokensFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletDetailsFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
|
|
@ -69,6 +70,7 @@ fun FragmentActivity.addOnBackPressedDispatcher(
|
|||
private fun fragmentFactory(screen: AppScreen): Fragment {
|
||||
return when (screen) {
|
||||
AppScreen.Home -> HomeFragment()
|
||||
AppScreen.Shop -> ShopFragment()
|
||||
AppScreen.OnboardingNote -> OnboardingNoteFragment()
|
||||
AppScreen.OnboardingWallet -> OnboardingWalletFragment()
|
||||
AppScreen.OnboardingTwins -> TwinsCardsFragment()
|
||||
|
|
|
|||
|
|
@ -68,9 +68,16 @@ fun View.hide(invokeBeforeStateChanged: (() -> Unit)? = null) {
|
|||
this.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.makeInvisible() {
|
||||
if (this.visibility == View.INVISIBLE) return
|
||||
this.visibility = View.INVISIBLE
|
||||
fun View.invisible(invisible: Boolean = true, invokeBeforeStateChanged: (() -> Unit)? = null) {
|
||||
if (invisible) {
|
||||
if (this.visibility == View.INVISIBLE) return
|
||||
|
||||
invokeBeforeStateChanged?.invoke()
|
||||
this.visibility = View.INVISIBLE
|
||||
} else {
|
||||
this.show(invokeBeforeStateChanged)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Context.dpToPixels(dp: Int): Int =
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ fun ViewGroup.beginDelayedTransition(transition: Transition = AutoTransition())
|
|||
TransitionManager.beginDelayedTransition(this, transition)
|
||||
}
|
||||
|
||||
fun View.beginDelayedTransition(transition: Transition = AutoTransition()) {
|
||||
(this as? ViewGroup)?.beginDelayedTransition(transition)
|
||||
}
|
||||
|
||||
fun ChipGroup.fitChipsByGroupWidth() {
|
||||
val layoutStateHandler = GlobalLayoutStateHandler(this)
|
||||
layoutStateHandler.onStateChanged = stateHandler@{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOt
|
|||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsReducer
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletReducer
|
||||
import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
|
||||
import com.tangem.tap.features.shop.redux.ShopReducer
|
||||
import com.tangem.tap.features.tokens.redux.TokensReducer
|
||||
import com.tangem.tap.features.wallet.redux.reducers.WalletReducer
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -32,7 +33,8 @@ fun appReducer(action: Action, state: AppState?): AppState {
|
|||
detailsState = DetailsReducer.reduce(action, state),
|
||||
disclaimerState = DisclaimerReducer.reduce(action, state),
|
||||
tokensState = TokensReducer.reduce(action, state),
|
||||
walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState)
|
||||
walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState),
|
||||
shopState = ShopReducer.reduce(action, state.shopState),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWallet
|
|||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.features.send.redux.middlewares.SendMiddleware
|
||||
import com.tangem.tap.features.send.redux.states.SendState
|
||||
import com.tangem.tap.features.shop.redux.ShopMiddleware
|
||||
import com.tangem.tap.features.shop.redux.ShopState
|
||||
import com.tangem.tap.features.tokens.redux.TokensMiddleware
|
||||
import com.tangem.tap.features.tokens.redux.TokensState
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
|
|
@ -44,6 +46,7 @@ data class AppState(
|
|||
val disclaimerState: DisclaimerState = DisclaimerState(),
|
||||
val tokensState: TokensState = TokensState(),
|
||||
val walletConnectState: WalletConnectState = WalletConnectState(),
|
||||
val shopState: ShopState = ShopState(),
|
||||
) : StateType {
|
||||
|
||||
companion object {
|
||||
|
|
@ -62,7 +65,8 @@ data class AppState(
|
|||
DisclaimerMiddleware().disclaimerMiddleware,
|
||||
TokensMiddleware().tokensMiddleware,
|
||||
WalletConnectMiddleware().walletConnectMiddleware,
|
||||
BackupMiddleware().backupMiddleware
|
||||
BackupMiddleware().backupMiddleware,
|
||||
ShopMiddleware().shopMiddleware,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ data class NavigationState(
|
|||
|
||||
enum class AppScreen {
|
||||
Home,
|
||||
Shop,
|
||||
Disclaimer,
|
||||
OnboardingNote, OnboardingWallet, OnboardingTwins, OnboardingOther,
|
||||
Wallet, WalletDetails,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
package com.tangem.tap.common.shop
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import com.google.android.gms.wallet.PaymentData
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.common.shop.data.TangemProduct
|
||||
import com.tangem.tap.common.shop.data.TotalSum
|
||||
import com.tangem.tap.common.shop.shopify.ShopifyShop
|
||||
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
|
||||
class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
|
||||
|
||||
private val shopifyService = ShopifyService(application, shopifyShop)
|
||||
|
||||
private lateinit var product: Storefront.Product
|
||||
|
||||
private val checkouts = mutableMapOf<ProductType, Storefront.Checkout>()
|
||||
private val variants = mutableMapOf<ProductType, Storefront.ProductVariant>()
|
||||
|
||||
private lateinit var googlePayService: GooglePayService
|
||||
|
||||
suspend fun getProducts(): Result<List<TangemProduct>> {
|
||||
val result = shopifyService.getProducts()
|
||||
|
||||
result.onSuccess {
|
||||
product = it.first {
|
||||
val variantsSku = it.variants.edges.map { it.node.sku }
|
||||
variantsSku.contains(ProductType.WALLET_2_CARDS.sku) && variantsSku.contains(
|
||||
ProductType.WALLET_3_CARDS.sku
|
||||
)
|
||||
}
|
||||
product.variants.edges.map { it.node }
|
||||
.forEach { variant ->
|
||||
if (variant.sku == ProductType.WALLET_2_CARDS.sku) {
|
||||
variants[ProductType.WALLET_2_CARDS] = variant
|
||||
} else if (variant.sku == ProductType.WALLET_3_CARDS.sku) {
|
||||
variants[ProductType.WALLET_3_CARDS] = variant
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val twoCardsProduct = TangemProduct(
|
||||
type = ProductType.WALLET_2_CARDS,
|
||||
totalSum = TotalSum(
|
||||
finalValue = variants[ProductType.WALLET_2_CARDS]?.priceV2?.format(),
|
||||
beforeDiscount = variants[ProductType.WALLET_2_CARDS]?.compareAtPriceV2?.format()
|
||||
)
|
||||
)
|
||||
val threeCardsProduct = TangemProduct(
|
||||
type = ProductType.WALLET_3_CARDS,
|
||||
totalSum = TotalSum(
|
||||
finalValue = variants[ProductType.WALLET_3_CARDS]?.priceV2?.format(),
|
||||
beforeDiscount = variants[ProductType.WALLET_3_CARDS]?.compareAtPriceV2?.format()
|
||||
)
|
||||
)
|
||||
createCheckouts()
|
||||
return Result.success(listOf(twoCardsProduct, threeCardsProduct))
|
||||
}
|
||||
return Result.failure(result.exceptionOrNull()!!)
|
||||
}
|
||||
|
||||
private suspend fun createCheckouts() {
|
||||
variants.keys.map { coroutineScope { async { createCheckout(it) } } }.awaitAll()
|
||||
}
|
||||
|
||||
private suspend fun createCheckout(productType: ProductType) {
|
||||
val checkoutItem = CheckoutItem(variants[productType]!!.id, 1)
|
||||
val result = shopifyService.createCheckout(listOf(checkoutItem))
|
||||
result.onSuccess { checkout ->
|
||||
checkouts[productType] = checkout
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun checkIfGooglePayAvailable(googlePayService: GooglePayService): Result<Boolean> {
|
||||
this.googlePayService = googlePayService
|
||||
return googlePayService.checkIfGooglePayAvailable()
|
||||
}
|
||||
|
||||
fun buyWithGooglePay(productType: ProductType) {
|
||||
val totalPrice = checkouts[productType]!!.totalPriceV2.amount
|
||||
googlePayService.payWithGooglePay(
|
||||
totalPriceCents = totalPrice, currencyCode = checkouts[productType]!!.currencyCode.name,
|
||||
merchantID = shopifyService.shop.merchantID
|
||||
)
|
||||
}
|
||||
|
||||
// fun subscribeToGooglePayResult(
|
||||
// productType: ProductType,
|
||||
// resultCallback: (Result<PaymentData>) -> Unit
|
||||
// ) {
|
||||
// googlePayService.responseCallback = { result ->
|
||||
// result.onFailure { }
|
||||
// result.onSuccess {
|
||||
// completeTokenizedPayment(it, productType)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
suspend fun handleGooglePayResult(
|
||||
resultCode: Int,
|
||||
data: Intent?,
|
||||
productType: ProductType
|
||||
): Result<Unit> {
|
||||
val result = googlePayService.handleResponseFromGooglePay(resultCode, data)
|
||||
result.onSuccess {
|
||||
val finalizePaymentResult = completeTokenizedPayment(it, productType)
|
||||
finalizePaymentResult.onSuccess {
|
||||
return Result.success(Unit)
|
||||
}
|
||||
return Result.failure(finalizePaymentResult.exceptionOrNull()!!)
|
||||
}
|
||||
return Result.failure(result.exceptionOrNull()!!)
|
||||
}
|
||||
|
||||
private suspend fun completeTokenizedPayment(
|
||||
paymentData: PaymentData,
|
||||
productType: ProductType
|
||||
): Result<Storefront.Checkout> {
|
||||
val checkout = checkouts[productType]!!
|
||||
val googlePayResponse =
|
||||
googlePayService.parsePaymentData(paymentData)
|
||||
?: return Result.failure(Exception("cannot parse GPay result"))
|
||||
|
||||
val amount =
|
||||
Storefront.MoneyInput(checkout.totalPriceV2.amount, checkout.totalPriceV2.currencyCode)
|
||||
val idempotencyKey = UUID.randomUUID().toString()
|
||||
val addressGPay = googlePayResponse.billingAddress
|
||||
|
||||
val address = Storefront.MailingAddressInput().apply {
|
||||
lastName = addressGPay.name
|
||||
address1 = addressGPay.address1
|
||||
address2 = addressGPay.address2 + addressGPay.address3
|
||||
province = addressGPay.administrativeArea
|
||||
zip = addressGPay.postalCode
|
||||
phone = addressGPay.phoneNumber
|
||||
}
|
||||
|
||||
|
||||
val payment = Storefront.TokenizedPaymentInputV3(
|
||||
amount,
|
||||
idempotencyKey,
|
||||
address,
|
||||
paymentData.toJson(),
|
||||
Storefront.PaymentTokenType.GOOGLE_PAY
|
||||
)
|
||||
.setTest(true)
|
||||
|
||||
return shopifyService.completeWithTokenizedPayment(
|
||||
payment = payment,
|
||||
checkoutID = checkout.id
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun applyPromoCode(promoCode: String): Result<List<TangemProduct>> {
|
||||
val products = variants.keys
|
||||
.map { coroutineScope { async { applyPromoCode(promoCode, it) } } }
|
||||
.awaitAll()
|
||||
.map { result -> result.getOrElse { return Result.failure(it) } }
|
||||
|
||||
return Result.success(products)
|
||||
}
|
||||
|
||||
suspend fun applyPromoCode(promoCode: String, productType: ProductType): Result<TangemProduct> {
|
||||
val checkout = checkouts[productType] ?: return Result.failure(Exception("No checkout"))
|
||||
|
||||
val result = if (promoCode.isBlank()) {
|
||||
shopifyService.removeDiscount(checkout.id)
|
||||
} else {
|
||||
shopifyService.applyDiscount(promoCode, checkout.id)
|
||||
}
|
||||
|
||||
result.onSuccess {
|
||||
checkouts[productType] = it
|
||||
return Result.success(
|
||||
TangemProduct(
|
||||
productType,
|
||||
TotalSum(
|
||||
finalValue = it.totalPriceV2.format(),
|
||||
beforeDiscount = variants[productType]!!.compareAtPriceV2.format()
|
||||
),
|
||||
appliedDiscount = it.getAppliedDiscount()
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
return Result.failure(result.exceptionOrNull()!!)
|
||||
}
|
||||
|
||||
fun getCheckoutUrl(productType: ProductType): String {
|
||||
return checkouts[productType]!!.webUrl
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TANGEM_WALLET_2_CARDS_SKU = "TG115x2"
|
||||
const val TANGEM_WALLET_3_CARDS_SKU = "TG115x3"
|
||||
}
|
||||
}
|
||||
|
||||
private fun Storefront.MoneyV2.format(): String {
|
||||
val currencySymbol = Currency.getInstance(currencyCode.name).symbol
|
||||
val amountFormatted = BigDecimal(amount).setScale(2)
|
||||
return currencySymbol + amountFormatted
|
||||
}
|
||||
|
||||
private fun Storefront.Checkout.getAppliedDiscount(): String? {
|
||||
val discountApplication =
|
||||
discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication
|
||||
return discountApplication?.code
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.common.shop.data
|
||||
|
||||
import com.tangem.tap.common.shop.TangemShopService
|
||||
|
||||
enum class ProductType(val sku: String) {
|
||||
WALLET_2_CARDS(TangemShopService.TANGEM_WALLET_2_CARDS_SKU),
|
||||
WALLET_3_CARDS(TangemShopService.TANGEM_WALLET_3_CARDS_SKU)
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.tap.common.shop.data
|
||||
|
||||
data class TangemProduct(
|
||||
val type: ProductType,
|
||||
val totalSum: TotalSum? = null,
|
||||
val appliedDiscount: String? = null
|
||||
)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.tap.common.shop.data
|
||||
|
||||
data class TotalSum(
|
||||
val finalValue: String? = null,
|
||||
val beforeDiscount: String? = null,
|
||||
)
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.tangem.tap.common.shop
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Activity.RESULT_CANCELED
|
||||
import android.app.Activity.RESULT_OK
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.google.android.gms.common.api.ApiException
|
||||
import com.google.android.gms.wallet.*
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.shop.googlepay.GooglePayUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import timber.log.Timber
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class GooglePayService(private val paymentsClient: PaymentsClient, private val activity: Activity) {
|
||||
|
||||
// var responseCallback: ((Result<PaymentData>) -> Unit)? = null
|
||||
|
||||
suspend fun checkIfGooglePayAvailable(): Result<Boolean> {
|
||||
|
||||
val isReadyToPayJson = GooglePayUtil.isReadyToPayRequest() ?: return Result.success(false)
|
||||
val request = IsReadyToPayRequest.fromJson(isReadyToPayJson.toString())
|
||||
|
||||
val task = paymentsClient.isReadyToPay(request)
|
||||
return withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
task.addOnCompleteListener { completedTask ->
|
||||
try {
|
||||
val result = completedTask.getResult(ApiException::class.java)
|
||||
continuation.resume(Result.success(true))
|
||||
} catch (exception: ApiException) {
|
||||
// Process error
|
||||
Timber.w("isReadyToPay failed: $exception")
|
||||
continuation.resume(Result.failure(exception))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun payWithGooglePay(totalPriceCents: String, currencyCode: String, merchantID: String) {
|
||||
val paymentDataRequestJson = GooglePayUtil.getPaymentDataRequest(
|
||||
totalPriceCents,
|
||||
currencyCode = currencyCode,
|
||||
countryCode = "RU",
|
||||
merchantID = merchantID
|
||||
)
|
||||
if (paymentDataRequestJson == null) {
|
||||
Timber.e("RequestPayment: can't fetch payment data request")
|
||||
return
|
||||
}
|
||||
val request = PaymentDataRequest.fromJson(paymentDataRequestJson.toString())
|
||||
|
||||
AutoResolveHelper.resolveTask(
|
||||
paymentsClient.loadPaymentData(request), activity, LOAD_PAYMENT_DATA_REQUEST_CODE
|
||||
)
|
||||
}
|
||||
|
||||
fun handleResponseFromGooglePay(resultCode: Int, data: Intent?): Result<PaymentData> {
|
||||
val result = when (resultCode) {
|
||||
RESULT_OK -> {
|
||||
val paymentData = data?.let { intent -> PaymentData.getFromIntent(intent) }
|
||||
if (paymentData == null) {
|
||||
Result.failure(Exception("No payment data"))
|
||||
} else {
|
||||
Result.success(paymentData)
|
||||
}
|
||||
}
|
||||
RESULT_CANCELED -> {
|
||||
Result.failure(TangemSdkError.UserCancelled())
|
||||
}
|
||||
AutoResolveHelper.RESULT_ERROR -> {
|
||||
val statusCode = AutoResolveHelper.getStatusFromIntent(data)?.statusCode
|
||||
if (statusCode == null) {
|
||||
Result.failure(Exception("Unknown Status"))
|
||||
} else {
|
||||
Result.failure(Exception("$statusCode"))
|
||||
}
|
||||
|
||||
}
|
||||
else -> Result.failure(Exception("Unknown Status"))
|
||||
}
|
||||
// responseCallback?.invoke(result)
|
||||
return result
|
||||
}
|
||||
|
||||
fun parsePaymentData(paymentData: PaymentData): GooglePayResponse? {
|
||||
val paymentInformation = paymentData.toJson()
|
||||
|
||||
try {
|
||||
// Token will be null if PaymentDataRequest was not constructed using fromJson(String).
|
||||
val paymentMethodData =
|
||||
JSONObject(paymentInformation).getJSONObject("paymentMethodData")
|
||||
val addressJson = paymentMethodData.getJSONObject("info")
|
||||
.getJSONObject("billingAddress")
|
||||
|
||||
val address = Address(
|
||||
name = addressJson.getString("name"),
|
||||
postalCode = addressJson.getString("postalCode"),
|
||||
countryCode = addressJson.getString("countryCode"),
|
||||
phoneNumber = addressJson.getString("phoneNumber"),
|
||||
address1 = addressJson.getString("address1"),
|
||||
address2 = addressJson.getString("address2"),
|
||||
address3 = addressJson.getString("address3"),
|
||||
locality = addressJson.getString("locality"),
|
||||
administrativeArea = addressJson.getString("administrativeArea"),
|
||||
sortingCode = addressJson.getString("sortingCode"),
|
||||
)
|
||||
|
||||
val token = paymentMethodData
|
||||
.getJSONObject("tokenizationData")
|
||||
.getString("token")
|
||||
|
||||
return GooglePayResponse(address, token)
|
||||
|
||||
} catch (e: JSONException) {
|
||||
Log.e("handlePaymentSuccess", "Error: " + e.toString())
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LOAD_PAYMENT_DATA_REQUEST_CODE = 315
|
||||
}
|
||||
}
|
||||
|
||||
data class GooglePayResponse(
|
||||
val billingAddress: Address,
|
||||
val token: String,
|
||||
)
|
||||
|
||||
data class Address(
|
||||
val name: String,
|
||||
val postalCode: String,
|
||||
val countryCode: String,
|
||||
val phoneNumber: String,
|
||||
val address1: String,
|
||||
val address2: String,
|
||||
val address3: String,
|
||||
val locality: String,
|
||||
val administrativeArea: String,
|
||||
val sortingCode: String
|
||||
)
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package com.tangem.tap.common.shop.googlepay
|
||||
|
||||
import android.app.Activity
|
||||
import com.google.android.gms.wallet.PaymentsClient
|
||||
import com.google.android.gms.wallet.Wallet
|
||||
import com.google.android.gms.wallet.WalletConstants
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
object GooglePayUtil {
|
||||
private val baseRequest = JSONObject().apply {
|
||||
put("apiVersion", 2)
|
||||
put("apiVersionMinor", 0)
|
||||
}
|
||||
|
||||
private fun gatewayTokenizationSpecification(merchantID: String): JSONObject {
|
||||
return JSONObject().apply {
|
||||
put("type", "PAYMENT_GATEWAY")
|
||||
put(
|
||||
"parameters", JSONObject(
|
||||
mapOf(
|
||||
"gateway" to "shopify",
|
||||
"gatewayMerchantId" to merchantID
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val allowedCardNetworks = JSONArray(
|
||||
listOf(
|
||||
"AMEX",
|
||||
"DISCOVER",
|
||||
"INTERAC",
|
||||
"JCB",
|
||||
"MASTERCARD",
|
||||
"VISA"
|
||||
)
|
||||
)
|
||||
|
||||
private val allowedCardAuthMethods = JSONArray(
|
||||
listOf(
|
||||
"PAN_ONLY",
|
||||
"CRYPTOGRAM_3DS"
|
||||
)
|
||||
)
|
||||
|
||||
private fun baseCardPaymentMethod(): JSONObject {
|
||||
return JSONObject().apply {
|
||||
|
||||
val parameters = JSONObject().apply {
|
||||
put("allowedAuthMethods", allowedCardAuthMethods)
|
||||
put("allowedCardNetworks", allowedCardNetworks)
|
||||
put("billingAddressRequired", true)
|
||||
put("billingAddressParameters", JSONObject().apply {
|
||||
put("format", "FULL")
|
||||
})
|
||||
}
|
||||
|
||||
put("type", "CARD")
|
||||
put("parameters", parameters)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cardPaymentMethod(merchantID: String): JSONObject {
|
||||
val cardPaymentMethod = baseCardPaymentMethod()
|
||||
cardPaymentMethod.put("tokenizationSpecification", gatewayTokenizationSpecification(merchantID))
|
||||
|
||||
return cardPaymentMethod
|
||||
}
|
||||
|
||||
fun createPaymentsClient(activity: Activity): PaymentsClient {
|
||||
val walletOptions = Wallet.WalletOptions.Builder()
|
||||
.setEnvironment(PAYMENTS_ENVIRONMENT)
|
||||
.build()
|
||||
|
||||
return Wallet.getPaymentsClient(activity, walletOptions)
|
||||
}
|
||||
|
||||
fun isReadyToPayRequest(): JSONObject? {
|
||||
return try {
|
||||
baseRequest.apply {
|
||||
put("allowedPaymentMethods", JSONArray().put(baseCardPaymentMethod()))
|
||||
}
|
||||
|
||||
} catch (e: JSONException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTransactionInfo(
|
||||
price: String,
|
||||
countryCode: String,
|
||||
currencyCode: String
|
||||
): JSONObject {
|
||||
return JSONObject().apply {
|
||||
put("totalPrice", price)
|
||||
put("totalPriceStatus", "FINAL")
|
||||
put("countryCode", countryCode)
|
||||
put("currencyCode", currencyCode)
|
||||
}
|
||||
}
|
||||
|
||||
private val merchantInfo: JSONObject =
|
||||
JSONObject().put("merchantName", "Example Merchant")
|
||||
|
||||
|
||||
fun getPaymentDataRequest(
|
||||
price: String,
|
||||
countryCode: String,
|
||||
currencyCode: String,
|
||||
merchantID: String
|
||||
): JSONObject? {
|
||||
try {
|
||||
return baseRequest.apply {
|
||||
put("allowedPaymentMethods", JSONArray().put(cardPaymentMethod(merchantID)))
|
||||
put("transactionInfo", getTransactionInfo(price, countryCode, currencyCode))
|
||||
put("merchantInfo", merchantInfo)
|
||||
|
||||
// An optional shipping address requirement is a top-level property of the
|
||||
// PaymentDataRequest JSON object.
|
||||
val shippingAddressParameters = JSONObject().apply {
|
||||
put("phoneNumberRequired", false)
|
||||
// put("allowedCountryCodes", JSONArray(listOf("US", "GB")))
|
||||
}
|
||||
put("shippingAddressParameters", shippingAddressParameters)
|
||||
put("shippingAddressRequired", true)
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const val PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_TEST
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
package com.tangem.tap.common.shop
|
||||
|
||||
import android.app.Application
|
||||
import com.shopify.buy3.GraphCallResult
|
||||
import com.shopify.buy3.GraphClient
|
||||
import com.shopify.buy3.RetryHandler
|
||||
import com.shopify.buy3.Storefront.*
|
||||
import com.shopify.graphql.support.ID
|
||||
import com.shopify.graphql.support.Input
|
||||
import com.tangem.tap.common.shop.shopify.ShopifyShop
|
||||
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
|
||||
import com.tangem.tap.common.shop.shopify.data.checkoutFieldsFragment
|
||||
import com.tangem.tap.common.shop.shopify.data.collectionFieldsFragment
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
|
||||
class ShopifyService(private val application: Application, val shop: ShopifyShop) {
|
||||
val client: GraphClient by lazy { initClient() }
|
||||
|
||||
|
||||
suspend fun getShopName(): Result<String> {
|
||||
val query = query { rootQuery: QueryRootQuery ->
|
||||
rootQuery
|
||||
.shop { shopQuery: ShopQuery ->
|
||||
shopQuery
|
||||
.name()
|
||||
}
|
||||
}
|
||||
return when (val result = queryAsync(query)) {
|
||||
is GraphCallResult.Success -> {
|
||||
val name = result.response.data!!.shop.name
|
||||
Result.success(name)
|
||||
}
|
||||
is GraphCallResult.Failure -> {
|
||||
Result.failure(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getProducts(collectionTitleFilter: String? = null): Result<List<Product>> {
|
||||
val filter = collectionTitleFilter?.let { "title:\"$it\"" }
|
||||
|
||||
val query = query { rootQuery: QueryRootQuery ->
|
||||
rootQuery
|
||||
.collections(
|
||||
{ arg -> arg.first(250).query(filter) },
|
||||
) { collectionConnectionQuery ->
|
||||
collectionConnectionQuery.collectionFieldsFragment()
|
||||
}
|
||||
}
|
||||
return when (val result = queryAsync(query)) {
|
||||
is GraphCallResult.Success -> {
|
||||
val products = result.response.data!!.collections.edges
|
||||
.map { it.node.products }
|
||||
.flatMap { it.edges }
|
||||
.map { it.node }
|
||||
Result.success(products)
|
||||
}
|
||||
is GraphCallResult.Failure -> {
|
||||
Result.failure(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun checkout(pollUntilOrder: Boolean, checkoutID: ID): Result<Checkout> {
|
||||
|
||||
val query = query { rootQuery: QueryRootQuery ->
|
||||
rootQuery
|
||||
.node(checkoutID) { query ->
|
||||
query.onCheckout { checkoutQuery ->
|
||||
with(checkoutQuery) {
|
||||
checkoutFieldsFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val retryHandler = RetryHandler.build<QueryRoot>(
|
||||
1, TimeUnit.SECONDS
|
||||
) {
|
||||
this.retryWhen { result ->
|
||||
when (result) {
|
||||
is GraphCallResult.Success -> {
|
||||
val checkout = result.response.data?.node as? Checkout
|
||||
checkout == null
|
||||
}
|
||||
is GraphCallResult.Failure -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val result = if (pollUntilOrder) queryAsync(query, retryHandler) else queryAsync(query)
|
||||
return when (result) {
|
||||
is GraphCallResult.Success -> {
|
||||
val checkout = result.response.data!!.node as? Checkout
|
||||
if (checkout != null) {
|
||||
Result.success(checkout)
|
||||
} else {
|
||||
Result.failure(ShopifyError.Unknown)
|
||||
}
|
||||
|
||||
}
|
||||
is GraphCallResult.Failure -> {
|
||||
Result.failure(result.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createCheckout(
|
||||
checkoutItems: List<CheckoutItem>,
|
||||
checkoutID: ID? = null
|
||||
): Result<Checkout> {
|
||||
|
||||
|
||||
val storefrontLineItems: MutableList<CheckoutLineItemInput> = checkoutItems
|
||||
.map { CheckoutLineItemInput(it.quantity, it.id) }.toMutableList()
|
||||
|
||||
val query = if (checkoutID != null) {
|
||||
mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutLineItemsReplace(
|
||||
storefrontLineItems, checkoutID
|
||||
) { payloadQuery: CheckoutLineItemsReplacePayloadQuery ->
|
||||
payloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.userErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val input = CheckoutCreateInput()
|
||||
.setLineItemsInput(
|
||||
Input.value(storefrontLineItems)
|
||||
)
|
||||
mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutCreate(
|
||||
input
|
||||
) { payloadQuery: CheckoutCreatePayloadQuery ->
|
||||
payloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun applyDiscount(discountCode: String, checkoutID: ID): Result<Checkout> {
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutDiscountCodeApplyV2(
|
||||
discountCode, checkoutID
|
||||
) { payloadQuery: CheckoutDiscountCodeApplyV2PayloadQuery ->
|
||||
payloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun removeDiscount(checkoutID: ID): Result<Checkout> {
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutDiscountCodeRemove(
|
||||
checkoutID
|
||||
) { payloadQuery: CheckoutDiscountCodeRemovePayloadQuery ->
|
||||
payloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun updateAddress(
|
||||
address: MailingAddress,
|
||||
checkoutID: ID,
|
||||
waitForShippingRates: Boolean
|
||||
): Result<Checkout> {
|
||||
val input = MailingAddressInput()
|
||||
.setAddress1(address.address1)
|
||||
.setAddress2(address.address2)
|
||||
.setCity(address.city)
|
||||
.setCountry(address.country)
|
||||
.setFirstName(address.firstName)
|
||||
.setLastName(address.lastName)
|
||||
.setPhone(address.phone)
|
||||
.setProvince(address.province)
|
||||
.setZip(address.zip)
|
||||
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutShippingAddressUpdateV2(
|
||||
input, checkoutID
|
||||
) { shippingAddressUpdatePayloadQuery: CheckoutShippingAddressUpdateV2PayloadQuery ->
|
||||
shippingAddressUpdatePayloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.checkoutUserErrors { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun updateEmail(email: String?, checkoutID: ID): Result<Checkout> {
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutEmailUpdateV2(
|
||||
checkoutID, email
|
||||
) { emailUpdatePayloadQuery: CheckoutEmailUpdateV2PayloadQuery ->
|
||||
emailUpdatePayloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun updateShippingRate(handle: String?, checkoutID: ID): Result<Checkout> {
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutShippingLineUpdate(
|
||||
checkoutID, handle
|
||||
) { shippingLineUpdatePayloadQuery: CheckoutShippingLineUpdatePayloadQuery ->
|
||||
shippingLineUpdatePayloadQuery
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery.checkoutFieldsFragment()
|
||||
}
|
||||
.checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
suspend fun completeWithTokenizedPayment(
|
||||
payment: TokenizedPaymentInputV3,
|
||||
checkoutID: ID
|
||||
): Result<Checkout> {
|
||||
|
||||
val query = mutation { mutationQuery: MutationQuery ->
|
||||
mutationQuery
|
||||
.checkoutCompleteWithTokenizedPaymentV3(
|
||||
checkoutID, payment
|
||||
) { payloadQuery: CheckoutCompleteWithTokenizedPaymentV3PayloadQuery ->
|
||||
payloadQuery
|
||||
.payment { paymentQuery: PaymentQuery ->
|
||||
paymentQuery
|
||||
.ready()
|
||||
.errorMessage()
|
||||
}
|
||||
.checkout { checkoutQuery: CheckoutQuery ->
|
||||
checkoutQuery
|
||||
.ready()
|
||||
}
|
||||
.checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
|
||||
userErrorQuery
|
||||
.field()
|
||||
.message()
|
||||
}
|
||||
}
|
||||
}
|
||||
return runCheckoutMutation(query)
|
||||
}
|
||||
|
||||
fun startGooglePaySession() {
|
||||
// PaySession()
|
||||
}
|
||||
|
||||
private suspend fun runCheckoutMutation(mutation: MutationQuery): Result<Checkout> {
|
||||
return when (val result = mutationQueryAsync(mutation)) {
|
||||
is GraphCallResult.Success -> {
|
||||
val checkout = result.response.data!!.checkoutCreate?.checkout
|
||||
?: result.response.data!!.checkoutDiscountCodeApplyV2?.checkout
|
||||
?: result.response.data!!.checkoutDiscountCodeRemove?.checkout
|
||||
?: result.response.data!!.checkoutShippingAddressUpdateV2?.checkout
|
||||
?: result.response.data!!.checkoutEmailUpdateV2?.checkout
|
||||
?: result.response.data!!.checkoutShippingLineUpdate?.checkout
|
||||
?: result.response.data!!.checkoutCompleteWithTokenizedPaymentV3.checkout
|
||||
|
||||
Result.success(checkout)
|
||||
}
|
||||
is GraphCallResult.Failure -> Result.failure(result.error)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun queryAsync(
|
||||
query: QueryRootQuery,
|
||||
retryHandler: RetryHandler<QueryRoot>
|
||||
): GraphCallResult<QueryRoot> =
|
||||
withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.queryGraph(query).enqueue(retryHandler = retryHandler) { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun queryAsync(
|
||||
query: QueryRootQuery,
|
||||
): GraphCallResult<QueryRoot> =
|
||||
withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.queryGraph(query).enqueue { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun mutationQueryAsync(query: MutationQuery): GraphCallResult<Mutation> =
|
||||
withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
client.mutateGraph(query).enqueue { result ->
|
||||
continuation.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun initClient(): GraphClient {
|
||||
return GraphClient.build(
|
||||
application,
|
||||
shop.domain,
|
||||
shop.storefrontApiKey
|
||||
) {
|
||||
// httpCache(application.filesDir) {
|
||||
// cacheMaxSizeBytes = (1024 * 1024 * 10)
|
||||
// defaultCachePolicy =
|
||||
// HttpCachePolicy.Default.CACHE_FIRST.expireAfter(20, TimeUnit.MINUTES)
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sealed class ShopifyError : Throwable() {
|
||||
object Unknown : ShopifyError()
|
||||
object GooglePayFailed : ShopifyError()
|
||||
class UserError(val errorMessage: String)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.tap.common.shop.shopify
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class ShopifyShop(
|
||||
val domain: String,
|
||||
val storefrontApiKey: String,
|
||||
val merchantID: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
package com.tangem.tap.common.shop.shopify.data
|
||||
|
||||
import com.shopify.buy3.Storefront
|
||||
|
||||
fun Storefront.CheckoutQuery.checkoutFieldsFragment() {
|
||||
// id()
|
||||
ready()
|
||||
webUrl()
|
||||
currencyCode()
|
||||
lineItemsSubtotalPrice { it.amount() }
|
||||
totalPriceV2 {
|
||||
it.currencyCode()
|
||||
it.amount() }
|
||||
lineItems({ arg -> arg.first(250) }) {
|
||||
it.edges {
|
||||
it.node {
|
||||
// it.id()
|
||||
it.title()
|
||||
it.quantity()
|
||||
it.variant() {
|
||||
it.priceV2() { it.amount() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shippingLine {
|
||||
it.handle()
|
||||
it.title()
|
||||
it.priceV2 { it.amount() }
|
||||
}
|
||||
availableShippingRates {
|
||||
it.ready()
|
||||
it.shippingRates {
|
||||
it.handle()
|
||||
it.title()
|
||||
it.priceV2 { it.amount() }
|
||||
}
|
||||
}
|
||||
shippingAddress {
|
||||
it.address1()
|
||||
it.address2()
|
||||
it.city()
|
||||
// .company()
|
||||
it.country()
|
||||
// .countryCodeV2()
|
||||
it.firstName()
|
||||
// .formatted()
|
||||
// .formattedArea()
|
||||
// .id()
|
||||
it.lastName()
|
||||
// .latitude()
|
||||
// .longitude()
|
||||
// .name()
|
||||
it.phone()
|
||||
it.province()
|
||||
// .provinceCode()
|
||||
it.zip()
|
||||
}
|
||||
discountApplications({ arg -> arg.first(250) }) {
|
||||
it.edges {
|
||||
it.node {
|
||||
it.onDiscountCodeApplication {
|
||||
it.code()
|
||||
// .applicable()
|
||||
// .allocationMethod()
|
||||
// .targetSelection()
|
||||
// .targetType()
|
||||
it.value {
|
||||
it.onMoneyV2 {
|
||||
it.amount()
|
||||
}
|
||||
it.onPricingPercentageValue {
|
||||
it.percentage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
order {
|
||||
it.cancelReason()
|
||||
it.canceledAt()
|
||||
it.currencyCode()
|
||||
// .currentSubtotalPrice()
|
||||
// .currentTotalDuties()
|
||||
// .currentTotalPrice()
|
||||
// .currentTotalTax()
|
||||
it.customerLocale()
|
||||
it.customerUrl()
|
||||
// .discountApplications()
|
||||
it.edited()
|
||||
it.email()
|
||||
it.financialStatus()
|
||||
it.fulfillmentStatus()
|
||||
// .id()
|
||||
// .lineItems()
|
||||
// .metafield()
|
||||
// .metafields()
|
||||
it.name()
|
||||
it.orderNumber()
|
||||
// .originalTotalDuties()
|
||||
// .originalTotalPrice()
|
||||
it.phone()
|
||||
it.processedAt()
|
||||
it.shippingAddress {
|
||||
it.address1()
|
||||
it.address2()
|
||||
it.city()
|
||||
it.company()
|
||||
it.country()
|
||||
it.countryCodeV2()
|
||||
it.firstName()
|
||||
it.formatted()
|
||||
it.formattedArea()
|
||||
// .id()
|
||||
it.lastName()
|
||||
it.latitude()
|
||||
it.longitude()
|
||||
it.name()
|
||||
it.phone()
|
||||
it.province()
|
||||
it.provinceCode()
|
||||
it.zip()
|
||||
}
|
||||
// .shippingDiscountAllocations()
|
||||
it.statusUrl()
|
||||
// .subtotalPriceV2()
|
||||
// .successfulFulfillments()
|
||||
// .totalPriceV2()
|
||||
// .totalRefundedV2()
|
||||
// .totalShippingPriceV2()
|
||||
// .totalTaxV2()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.tap.common.shop.shopify.data
|
||||
|
||||
import com.shopify.graphql.support.ID
|
||||
|
||||
data class CheckoutItem(
|
||||
val id: ID,
|
||||
val quantity: Int
|
||||
)
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.tap.common.shop.shopify.data
|
||||
|
||||
import com.shopify.buy3.Storefront
|
||||
|
||||
fun Storefront.CollectionConnectionQuery.collectionFieldsFragment() {
|
||||
edges { collectionEdgeQuery ->
|
||||
collectionEdgeQuery
|
||||
.node { collectionQuery ->
|
||||
collectionQuery
|
||||
.title()
|
||||
.products({ arg -> arg.first(250) }
|
||||
) { productConnectionQuery ->
|
||||
productConnectionQuery
|
||||
.edges { productEdgeQuery ->
|
||||
productEdgeQuery
|
||||
.node { productQuery ->
|
||||
productQuery.title()
|
||||
.productType()
|
||||
.description()
|
||||
.variants({ arg -> arg.first(10) }) { variantConnectionQuery ->
|
||||
variantConnectionQuery.edges { variantQuery ->
|
||||
variantQuery.node {
|
||||
it.title()
|
||||
it.sku()
|
||||
it.currentlyNotInStock()
|
||||
it.priceV2 {
|
||||
it.amount()
|
||||
it.currencyCode()
|
||||
}
|
||||
it.compareAtPriceV2 {
|
||||
it.amount()
|
||||
it.currencyCode()
|
||||
}
|
||||
it.compareAtPriceV2 {
|
||||
it.amount()
|
||||
}
|
||||
it.product {
|
||||
it.title()
|
||||
.productType()
|
||||
.description()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.domain.configurable.config
|
|||
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.tap.common.shop.shopify.ShopifyShop
|
||||
import com.tangem.tap.domain.configurable.Loader
|
||||
|
||||
/**
|
||||
|
|
@ -16,7 +17,8 @@ data class Config(
|
|||
val isSendingToPayIdEnabled: Boolean = true,
|
||||
val isTopUpEnabled: Boolean = false,
|
||||
@Deprecated("Not relevant since version 3.23")
|
||||
val isCreatingTwinCardsAllowed: Boolean = false
|
||||
val isCreatingTwinCardsAllowed: Boolean = false,
|
||||
val shopify: ShopifyShop? = null
|
||||
)
|
||||
|
||||
class ConfigManager(
|
||||
|
|
@ -52,10 +54,10 @@ class ConfigManager(
|
|||
fun resetToDefault(name: String) {
|
||||
when (name) {
|
||||
isSendingToPayIdEnabled -> config =
|
||||
config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled)
|
||||
config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled)
|
||||
isTopUpEnabled -> config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled)
|
||||
isCreatingTwinCardsAllowed -> config =
|
||||
config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed)
|
||||
config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +89,7 @@ class ConfigManager(
|
|||
infuraProjectId = values.infuraProjectId
|
||||
),
|
||||
appsFlyerDevKey = values.appsFlyerDevKey,
|
||||
shopify = values.shopifyShop,
|
||||
)
|
||||
defaultConfig = defaultConfig.copy(
|
||||
coinMarketCapKey = values.coinMarketCapKey,
|
||||
|
|
@ -99,6 +102,7 @@ class ConfigManager(
|
|||
infuraProjectId = values.infuraProjectId
|
||||
),
|
||||
appsFlyerDevKey = values.appsFlyerDevKey,
|
||||
shopify = values.shopifyShop,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.tap.domain.configurable.config
|
||||
|
||||
import com.tangem.tap.common.shop.shopify.ShopifyShop
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
|
@ -20,6 +22,7 @@ class ConfigValueModel(
|
|||
val blockcypherTokens: Set<String>?,
|
||||
val infuraProjectId: String?,
|
||||
val appsFlyerDevKey: String,
|
||||
val shopifyShop: ShopifyShop?
|
||||
)
|
||||
|
||||
class ConfigModel(val features: FeatureModel?, val configValues: ConfigValueModel?) {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
|
|||
}
|
||||
ConfirmScreenState.LongTap, ConfirmScreenState.AccessCode,
|
||||
ConfirmScreenState.PassCode -> {
|
||||
toolbar.title = getString(R.string.details_row_title_manage_security)
|
||||
toolbar.title = getString(R.string.details_manage_security_title)
|
||||
tv_warning_description.text = getString(R.string.details_security_management_warning)
|
||||
btn_confirm.text = getString(R.string.common_save_changes)
|
||||
btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
|
||||
}
|
||||
|
||||
tv_security_title.setOnClickListener {
|
||||
ll_manage_security.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ManageSecurity.CheckCurrentSecurityOption(state.scanResponse!!.card))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import com.tangem.common.card.Card
|
|||
import com.tangem.tap.common.extensions.sendEmail
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.domain.TapWorkarounds
|
||||
import com.tangem.tap.features.feedback.EmailData.Companion.appendBlankLine
|
||||
import com.tangem.tap.features.feedback.EmailData.Companion.appendDelimiter
|
||||
import com.tangem.wallet.R
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
|
|
@ -40,7 +43,8 @@ class FeedbackManager(
|
|||
val fileLog = if (emailData is ScanFailsEmail) createLogFile() else null
|
||||
activity.sendEmail(
|
||||
email = getSupportEmail(),
|
||||
subject = emailData.subject, message = emailData.joinTogether(infoHolder, emailData !is ScanFailsEmail),
|
||||
subject = activity.getString(emailData.subjectResId),
|
||||
message = emailData.joinTogether(activity, infoHolder),
|
||||
file = fileLog,
|
||||
onFail = onFail
|
||||
)
|
||||
|
|
@ -142,7 +146,7 @@ class AdditionalEmailInfo {
|
|||
cardFirmwareVersion = card.firmwareVersion.stringValue
|
||||
cardIssuer = card.issuer.name
|
||||
signedHashesCount = card.wallets
|
||||
.joinToString(";") { "${it.curve?.curve} - ${it.totalSignedHashes}" }
|
||||
.joinToString(";") { "${it.curve?.curve} - ${it.totalSignedHashes}" }
|
||||
}
|
||||
|
||||
fun setWalletsInfo(walletManagers: List<WalletManager>) {
|
||||
|
|
@ -201,43 +205,40 @@ class AdditionalEmailInfo {
|
|||
}
|
||||
|
||||
interface EmailData {
|
||||
val subject: String
|
||||
val mainMessage: String
|
||||
val subjectResId: Int
|
||||
val mainMessageResId: Int
|
||||
|
||||
fun getDataCollectionMessageResId(): Int = R.string.feedback_data_collection_message
|
||||
|
||||
fun prepare(infoHolder: AdditionalEmailInfo) {}
|
||||
|
||||
fun appendDelimiter(builder: StringBuilder) {
|
||||
builder.append("----------\n")
|
||||
}
|
||||
|
||||
fun appendBlankLine(builder: StringBuilder) {
|
||||
builder.append("\n")
|
||||
}
|
||||
|
||||
fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String
|
||||
|
||||
fun joinTogether(infoHolder: AdditionalEmailInfo, allowToErasePhoneInfo: Boolean): String {
|
||||
val allowToErasePhoneInfoDisclaimer = if (allowToErasePhoneInfo) {
|
||||
"Following information is optional. You can erase it if you don’t want to share it.\n\n"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
return "$mainMessage\n\n\n\n" +
|
||||
allowToErasePhoneInfoDisclaimer +
|
||||
createOptionalMessage(infoHolder)
|
||||
fun joinTogether(context: Context, infoHolder: AdditionalEmailInfo): String {
|
||||
return StringBuilder().apply {
|
||||
append(context.getString(mainMessageResId))
|
||||
append("\n\n\n\n")
|
||||
append(context.getString(getDataCollectionMessageResId()))
|
||||
append(createOptionalMessage(infoHolder))
|
||||
}.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun StringBuilder.appendDelimiter() = append("----------\n")
|
||||
internal fun StringBuilder.appendBlankLine() = append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
class RateCanBeBetterEmail : EmailData {
|
||||
override val subject: String = "My suggestions"
|
||||
override val mainMessage: String = "Tell us what functions you are missing, and we will try to help you."
|
||||
override val subjectResId: Int = R.string.feedback_subject_rate_negative
|
||||
override val mainMessageResId: Int = R.string.feedback_preface_rate_negative
|
||||
|
||||
override fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String {
|
||||
val walletInfo = infoHolder.walletsInfo[0]
|
||||
return StringBuilder().apply {
|
||||
appendKeyValue("Card ID", infoHolder.cardId)
|
||||
appendKeyValue("Blockchain", walletInfo.blockchain.fullName)
|
||||
appendBlankLine(this)
|
||||
appendBlankLine()
|
||||
appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
appendKeyValue("OS version", infoHolder.osVersion)
|
||||
appendKeyValue("App version", infoHolder.appVersion)
|
||||
|
|
@ -246,11 +247,21 @@ class RateCanBeBetterEmail : EmailData {
|
|||
}
|
||||
|
||||
class ScanFailsEmail : EmailData {
|
||||
override val subject: String = "Can’t scan a card"
|
||||
override val mainMessage: String = "Please tell us what card do you have?"
|
||||
|
||||
override val subjectResId: Int = R.string.feedback_subject_scan_failed
|
||||
override val mainMessageResId: Int = R.string.feedback_preface_scan_failed
|
||||
|
||||
override fun joinTogether(context: Context, infoHolder: AdditionalEmailInfo): String {
|
||||
return StringBuilder().apply {
|
||||
append(context.getString(mainMessageResId))
|
||||
append("\n\n\n\n")
|
||||
append(createOptionalMessage(infoHolder))
|
||||
}.toString()
|
||||
}
|
||||
|
||||
override fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String {
|
||||
return StringBuilder().apply {
|
||||
appendBlankLine(this)
|
||||
appendBlankLine()
|
||||
appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
appendKeyValue("OS version", infoHolder.osVersion)
|
||||
appendKeyValue("App version", infoHolder.appVersion)
|
||||
|
|
@ -259,8 +270,8 @@ class ScanFailsEmail : EmailData {
|
|||
}
|
||||
|
||||
class SendTransactionFailedEmail(private val error: String) : EmailData {
|
||||
override val subject: String = "Can’t send a transaction"
|
||||
override val mainMessage: String = "Please tell us more about your issue. Every small detail can help."
|
||||
override val subjectResId: Int = R.string.feedback_subject_tx_failed
|
||||
override val mainMessageResId: Int = R.string.feedback_preface_tx_failed
|
||||
|
||||
override fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String {
|
||||
val walletInfo = infoHolder.onSendErrorWalletInfo ?: AdditionalEmailInfo.EmailWalletInfo()
|
||||
|
|
@ -268,17 +279,17 @@ class SendTransactionFailedEmail(private val error: String) : EmailData {
|
|||
appendKeyValue("Card ID", infoHolder.cardId)
|
||||
appendKeyValue("Firmware version", infoHolder.cardFirmwareVersion)
|
||||
appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
appendDelimiter(this)
|
||||
appendDelimiter()
|
||||
appendKeyValue("Blockchain", walletInfo.blockchain.fullName)
|
||||
appendKeyValue("Host", walletInfo.host)
|
||||
appendKeyValue("Token", infoHolder.token)
|
||||
appendKeyValue("Error", error)
|
||||
appendDelimiter(this)
|
||||
appendDelimiter()
|
||||
appendKeyValue("Source address", walletInfo.address)
|
||||
appendKeyValue("Destination address", infoHolder.destinationAddress)
|
||||
appendKeyValue("Amount", infoHolder.amount)
|
||||
appendKeyValue("Fee", infoHolder.fee)
|
||||
appendBlankLine(this)
|
||||
appendBlankLine()
|
||||
appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
appendKeyValue("OS version", infoHolder.osVersion)
|
||||
appendKeyValue("App version", infoHolder.appVersion)
|
||||
|
|
@ -288,16 +299,16 @@ class SendTransactionFailedEmail(private val error: String) : EmailData {
|
|||
}
|
||||
|
||||
class FeedbackEmail : EmailData {
|
||||
override val subject: String
|
||||
override val subjectResId: Int
|
||||
get() = if (isS2CCard) s2cSubject else tangemSubject
|
||||
override val mainMessage: String
|
||||
override val mainMessageResId: Int
|
||||
get() = if (isS2CCard) s2cMainMessage else tangemMainMessage
|
||||
|
||||
private val tangemSubject = "Tangem feedback"
|
||||
private val tangemMainMessage = "Hi support team,"
|
||||
private val tangemSubject: Int = R.string.feedback_subject_support_tangem
|
||||
private val tangemMainMessage: Int = R.string.feedback_preface_support
|
||||
|
||||
private val s2cSubject = "Feedback"
|
||||
private val s2cMainMessage = "Hi support team,"
|
||||
private val s2cSubject: Int = R.string.feedback_subject_support
|
||||
private val s2cMainMessage: Int = R.string.feedback_preface_support
|
||||
|
||||
private var isS2CCard = false
|
||||
|
||||
|
|
@ -312,26 +323,26 @@ class FeedbackEmail : EmailData {
|
|||
builder.appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
|
||||
infoHolder.walletsInfo.forEach {
|
||||
appendDelimiter(builder)
|
||||
builder.appendDelimiter()
|
||||
builder.appendKeyValue("Blockchain", it.blockchain.fullName)
|
||||
builder.appendKeyValue("Host", it.host)
|
||||
builder.appendKeyValue("Wallet address", it.address)
|
||||
builder.appendKeyValue("Explorer link", it.explorerLink)
|
||||
}
|
||||
appendBlankLine(builder)
|
||||
builder.appendBlankLine()
|
||||
|
||||
infoHolder.tokens.forEach { tokens ->
|
||||
appendDelimiter(builder)
|
||||
builder.appendDelimiter()
|
||||
builder.appendKeyValue("Blockchain", tokens.key.fullName)
|
||||
builder.appendKeyValue("Tokens", tokens.value.map { "${it.name} - ${it.symbol}" }.toString())
|
||||
}
|
||||
appendDelimiter(builder)
|
||||
appendBlankLine(builder)
|
||||
|
||||
builder.appendDelimiter()
|
||||
builder.appendBlankLine()
|
||||
// appendKeyValue("Outputs count", infoHolder.outputsCount)
|
||||
builder.appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
builder.appendKeyValue("OS version", infoHolder.osVersion)
|
||||
builder.appendKeyValue("App version", infoHolder.appVersion)
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.tangem.tap.common.analytics.AnalyticsEvent
|
|||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.GetCardSourceParams
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.onCardScanned
|
||||
import com.tangem.tap.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.post
|
||||
|
|
@ -50,7 +49,7 @@ private val homeMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
}
|
||||
is HomeAction.ReadCard -> handleReadCard()
|
||||
is HomeAction.GoToShop -> {
|
||||
store.dispatchOpenUrl(HomeMiddleware.CARD_SHOP_URI)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
|
||||
store.state.globalState.analyticsHandlers?.triggerEvent(
|
||||
event = AnalyticsEvent.GET_CARD,
|
||||
params = mapOf(AnalyticsParam.SOURCE.param to GetCardSourceParams.WELCOME.param)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class AddressInfoBottomSheetDialog(
|
|||
btn_fl_share.setOnClickListener {
|
||||
store.dispatchShare(data.shareUrl)
|
||||
}
|
||||
tv_recieve_message.text = getQRReceiveMessage(tv_recieve_message.context, stateDialog.currency)
|
||||
tv_receive_message.text = getQRReceiveMessage(tv_receive_message.context, stateDialog.currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
StoreSubscriber<OnboardingWalletState>, FragmentOnBackPressedHandler {
|
||||
|
||||
private var accessCodeDialog: AccessCodeDialog? = null
|
||||
private lateinit var cardsWidget: BackupCardsWidget
|
||||
private lateinit var cardsWidget: WalletCardsWidget
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -48,7 +48,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val leapfrog = LeapfrogWidget(fl_cards_container)
|
||||
cardsWidget = BackupCardsWidget(leapfrog) { 200f }
|
||||
cardsWidget = WalletCardsWidget(leapfrog) { 200f }
|
||||
startPostponedEnterTransition()
|
||||
|
||||
view_pager_backup_info.adapter = BackupInfoAdapter()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapView
|
|||
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapViewState
|
||||
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
|
||||
|
||||
class BackupCardsWidget(
|
||||
class WalletCardsWidget(
|
||||
val leapfrogWidget: LeapfrogWidget,
|
||||
val getTopOfAnchorViewForActivateState: () -> Float,
|
||||
) {
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.tap.features.shop.redux
|
||||
|
||||
import android.content.Intent
|
||||
import com.tangem.tap.common.shop.GooglePayService
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.common.shop.data.TangemProduct
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class ShopAction : Action {
|
||||
|
||||
object LoadProducts : ShopAction() {
|
||||
data class Success(val products: List<TangemProduct>) : ShopAction()
|
||||
}
|
||||
|
||||
data class ApplyPromoCode(val promoCode: String) : ShopAction() {
|
||||
data class Success(val promoCode: String?, val products: List<TangemProduct>) : ShopAction()
|
||||
object InvalidPromoCode : ShopAction()
|
||||
}
|
||||
|
||||
object BuyWithGooglePay : ShopAction() {
|
||||
object UserCancelled : ShopAction()
|
||||
data class HandleGooglePayResponse(val resultCode: Int, val data: Intent?) : ShopAction()
|
||||
|
||||
data class Failure(val exception: Throwable) : ShopAction()
|
||||
object Success : ShopAction()
|
||||
}
|
||||
|
||||
object StartWebCheckout : ShopAction()
|
||||
|
||||
data class CheckIfGooglePayAvailable(val googlePayService: GooglePayService) : ShopAction() {
|
||||
object Success : ShopAction()
|
||||
object Failure : ShopAction()
|
||||
}
|
||||
|
||||
data class SelectProduct(val productType: ProductType) : ShopAction()
|
||||
|
||||
object ResetState : ShopAction()
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package com.tangem.tap.features.shop.redux
|
||||
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
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.scope
|
||||
import com.tangem.tap.shopService
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class ShopMiddleware {
|
||||
|
||||
val shopMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
handle(action)
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handle(action: Action) {
|
||||
|
||||
val shopState = store.state.shopState
|
||||
|
||||
if (action is NavigationAction.NavigateTo && action.screen == AppScreen.Shop) {
|
||||
store.dispatch(ShopAction.LoadProducts)
|
||||
}
|
||||
|
||||
if (action !is ShopAction) return
|
||||
|
||||
when (action) {
|
||||
is ShopAction.ApplyPromoCode -> {
|
||||
scope.launch {
|
||||
if (action.promoCode.isBlank() && shopState.promoCode == null) {
|
||||
store.dispatchOnMain(ShopAction.ApplyPromoCode.InvalidPromoCode)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val result = shopService.applyPromoCode(action.promoCode)
|
||||
|
||||
result.onSuccess { products ->
|
||||
store.dispatchOnMain(
|
||||
ShopAction.ApplyPromoCode.Success(
|
||||
promoCode = products.first { it.type == shopState.selectedProduct }.appliedDiscount,
|
||||
products = products
|
||||
)
|
||||
)
|
||||
}
|
||||
result.onFailure { store.dispatchOnMain(ShopAction.ApplyPromoCode.InvalidPromoCode) }
|
||||
}
|
||||
}
|
||||
ShopAction.BuyWithGooglePay -> {
|
||||
shopService.buyWithGooglePay(shopState.selectedProduct)
|
||||
// shopService.subscribeToGooglePayResult(productType = shopState.selectedProduct) { result ->
|
||||
// result.onSuccess {
|
||||
// store.dispatch(ShopAction.BuyWithGooglePay.Success)
|
||||
// }
|
||||
// result.onFailure { error ->
|
||||
// if (error is TangemSdkError.UserCancelled) {
|
||||
// store.dispatch(ShopAction.BuyWithGooglePay.UserCancelled)
|
||||
// } else {
|
||||
// store.dispatch(ShopAction.BuyWithGooglePay.Failure(error))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
is ShopAction.BuyWithGooglePay.HandleGooglePayResponse -> {
|
||||
scope.launch {
|
||||
val result = shopService.handleGooglePayResult(
|
||||
action.resultCode,
|
||||
action.data,
|
||||
shopState.selectedProduct
|
||||
)
|
||||
result.onSuccess {
|
||||
store.dispatchOnMain(ShopAction.BuyWithGooglePay.Success)
|
||||
}
|
||||
result.onFailure {
|
||||
store.dispatchOnMain(ShopAction.BuyWithGooglePay.Failure(it))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ShopAction.LoadProducts -> {
|
||||
scope.launch {
|
||||
val result = shopService.getProducts()
|
||||
result.onSuccess {
|
||||
store.dispatchOnMain(ShopAction.LoadProducts.Success(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
is ShopAction.CheckIfGooglePayAvailable -> {
|
||||
scope.launch {
|
||||
val isAvailable =
|
||||
shopService.checkIfGooglePayAvailable(action.googlePayService).getOrNull()
|
||||
?: false
|
||||
val newAction = if (isAvailable) {
|
||||
ShopAction.CheckIfGooglePayAvailable.Success
|
||||
} else {
|
||||
ShopAction.CheckIfGooglePayAvailable.Failure
|
||||
}
|
||||
store.dispatchOnMain(newAction)
|
||||
|
||||
}
|
||||
}
|
||||
ShopAction.StartWebCheckout -> {
|
||||
store.dispatchOpenUrl(shopService.getCheckoutUrl(shopState.selectedProduct))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.tangem.tap.features.shop.redux
|
||||
|
||||
import org.rekotlin.Action
|
||||
|
||||
class ShopReducer {
|
||||
companion object {
|
||||
fun reduce(action: Action, state: ShopState): ShopState = internalReduce(action, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, state: ShopState): ShopState {
|
||||
|
||||
if (action !is ShopAction) return state
|
||||
|
||||
return when (action) {
|
||||
is ShopAction.ApplyPromoCode -> state.copy(
|
||||
promoCode = action.promoCode,
|
||||
promoCodeLoading = true
|
||||
)
|
||||
ShopAction.BuyWithGooglePay -> state
|
||||
ShopAction.LoadProducts -> state
|
||||
is ShopAction.LoadProducts.Success -> {
|
||||
state.copy(
|
||||
availableProducts = action.products,
|
||||
)
|
||||
}
|
||||
ShopAction.StartWebCheckout -> state
|
||||
ShopAction.ApplyPromoCode.InvalidPromoCode -> state.copy(
|
||||
promoCode = null, promoCodeLoading = false
|
||||
)
|
||||
is ShopAction.ApplyPromoCode.Success -> {
|
||||
state.copy(
|
||||
promoCode = action.promoCode,
|
||||
availableProducts = action.products,
|
||||
promoCodeLoading = false
|
||||
|
||||
)
|
||||
}
|
||||
is ShopAction.SelectProduct -> {
|
||||
state.copy(
|
||||
selectedProduct = action.productType,
|
||||
)
|
||||
}
|
||||
is ShopAction.CheckIfGooglePayAvailable -> {
|
||||
state
|
||||
}
|
||||
ShopAction.CheckIfGooglePayAvailable.Failure -> {
|
||||
state.copy(isGooglePayAvailable = false)
|
||||
}
|
||||
ShopAction.CheckIfGooglePayAvailable.Success -> {
|
||||
state.copy(isGooglePayAvailable = false) // TODO: change when we add support for GPay
|
||||
|
||||
}
|
||||
is ShopAction.BuyWithGooglePay.Failure -> {
|
||||
state
|
||||
}
|
||||
is ShopAction.BuyWithGooglePay.HandleGooglePayResponse -> {
|
||||
state
|
||||
}
|
||||
ShopAction.BuyWithGooglePay.Success -> {
|
||||
state
|
||||
}
|
||||
ShopAction.BuyWithGooglePay.UserCancelled -> {
|
||||
state
|
||||
}
|
||||
ShopAction.ResetState -> ShopState()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.shop.redux
|
||||
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.common.shop.data.TangemProduct
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class ShopState(
|
||||
val availableProducts: List<TangemProduct> = emptyList(),
|
||||
val selectedProduct: ProductType = ProductType.WALLET_3_CARDS,
|
||||
val promoCode: String? = null,
|
||||
val promoCodeLoading: Boolean = false,
|
||||
val isGooglePayAvailable: Boolean = false, // TODO: change when we add support for GPay
|
||||
) : StateType {
|
||||
val total: String?
|
||||
get() = availableProducts.firstOrNull { it.type == selectedProduct }?.totalSum?.finalValue
|
||||
|
||||
val priceBeforeDiscount: String?
|
||||
get() {
|
||||
val totalSum = availableProducts.firstOrNull { it.type == selectedProduct }?.totalSum
|
||||
if (totalSum?.finalValue != totalSum?.beforeDiscount) {
|
||||
return totalSum?.beforeDiscount
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
package com.tangem.tap.features.shop.ui
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.View.OnFocusChangeListener
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.features.BaseStoreFragment
|
||||
import com.tangem.tap.features.shop.redux.ShopAction
|
||||
import com.tangem.tap.features.shop.redux.ShopState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_shop.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
|
||||
class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<ShopState> {
|
||||
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.shopState == newState.shopState
|
||||
}.select { it.shopState }
|
||||
}
|
||||
storeSubscribersList.add(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
store.dispatch(ShopAction.ResetState)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setupCardsImages()
|
||||
setupProductSelection()
|
||||
setupPromoCodeEditText()
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
requireActivity().onBackPressed()
|
||||
}
|
||||
|
||||
|
||||
val keyboardObserver = KeyboardObserver(requireActivity())
|
||||
keyboardObserver.registerListener { isVisible ->
|
||||
fl_cards.show(!isVisible)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCardsImages() {
|
||||
imv_second.animate()
|
||||
.translationY(70f)
|
||||
.scaleX(0.9f)
|
||||
.scaleY(0.9f)
|
||||
.start()
|
||||
imv_third.animate()
|
||||
.translationY(140f)
|
||||
.scaleX(0.8f)
|
||||
.scaleY(0.8f)
|
||||
.start()
|
||||
}
|
||||
|
||||
private fun setupProductSelection() {
|
||||
chip_product_1.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) store.dispatch(ShopAction.SelectProduct(ProductType.WALLET_3_CARDS))
|
||||
}
|
||||
chip_product_2.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) store.dispatch(ShopAction.SelectProduct(ProductType.WALLET_2_CARDS))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPromoCodeEditText() {
|
||||
et_promo_code.setOnEditorActionListener { view, actionId, event ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
val imm: InputMethodManager =
|
||||
requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
view.clearFocus()
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
|
||||
et_promo_code.onFocusChangeListener = OnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
store.dispatch(ShopAction.ApplyPromoCode(et_promo_code.text.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newState(state: ShopState) {
|
||||
if (activity == null) return
|
||||
|
||||
animateProductSelection(state.selectedProduct)
|
||||
handlePriceState(state)
|
||||
handlePromoCodeState(state)
|
||||
handleButtonsState(state)
|
||||
}
|
||||
|
||||
private fun animateProductSelection(selectedProduct: ProductType) {
|
||||
val show = when (selectedProduct) {
|
||||
ProductType.WALLET_2_CARDS -> false
|
||||
ProductType.WALLET_3_CARDS -> true
|
||||
}
|
||||
showOrHideThirdCardWithAnimation(show)
|
||||
}
|
||||
|
||||
private fun showOrHideThirdCardWithAnimation(show: Boolean) {
|
||||
val translationY = if (show) 140f else 0f
|
||||
if (show) imv_third.show()
|
||||
imv_third.animate()
|
||||
.translationY(translationY)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
imv_third?.show(show)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handlePriceState(state: ShopState) {
|
||||
tv_total.text = state.total
|
||||
tv_total_before_discount.text = state.priceBeforeDiscount
|
||||
|
||||
pb_price.show(state.total == null)
|
||||
|
||||
}
|
||||
|
||||
private fun handlePromoCodeState(state: ShopState) {
|
||||
if (state.promoCode == null && !et_promo_code.hasFocus()) {
|
||||
et_promo_code.setText("")
|
||||
}
|
||||
pb_promo_code.show(state.promoCodeLoading)
|
||||
}
|
||||
|
||||
private fun handleButtonsState(state: ShopState) {
|
||||
btn_pay_google_pay.show(state.isGooglePayAvailable)
|
||||
btn_alternative_payment.show(state.isGooglePayAvailable)
|
||||
btn_main_action.show(!state.isGooglePayAvailable)
|
||||
|
||||
if (state.total != null) {
|
||||
btn_alternative_payment.setOnClickListener { store.dispatch(ShopAction.StartWebCheckout) }
|
||||
btn_main_action.setOnClickListener { store.dispatch(ShopAction.StartWebCheckout) }
|
||||
btn_pay_google_pay.setOnClickListener { store.dispatch(ShopAction.BuyWithGooglePay) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
store.dispatch(ShopAction.ResetState)
|
||||
super.handleOnBackPressed()
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import androidx.appcompat.widget.SearchView
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
import com.tangem.tap.features.tokens.redux.TokensState
|
||||
|
|
@ -96,7 +97,7 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens),
|
|||
|
||||
val menuItem = menu.findItem(R.id.menu_search)
|
||||
val searchView: SearchView = menuItem.actionView as SearchView
|
||||
searchView.queryHint = "Type here to search"
|
||||
searchView.queryHint = searchView.getString(R.string.add_token_search_hint)
|
||||
searchView.maxWidth = android.R.attr.width
|
||||
searchView.inputtedTextAsFlow()
|
||||
.debounce(400)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
|
|||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.item_currency_wallet.view.*
|
||||
import kotlinx.android.synthetic.main.item_popular_token.view.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_error.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.layout_wallet_details.*
|
||||
|
|
@ -197,7 +195,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
requireContext()))
|
||||
}
|
||||
iv_qr_code.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode())
|
||||
tv_recieve_message.text = getQRReceiveMessage(tv_recieve_message.context, state.currency)
|
||||
tv_receive_message.text = getQRReceiveMessage(tv_receive_message.context, state.currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
11
app/src/main/res/color/selector_chip_shop.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 24% opacity -->
|
||||
<item android:color="@color/chipBlack" android:state_enabled="true" android:state_selected="true" />
|
||||
|
||||
<item android:color="@color/chipBlack" android:state_checked="true" android:state_enabled="true" />
|
||||
|
||||
<item android:color="@color/backgroundGray" android:state_enabled="true" />
|
||||
<item android:color="@color/backgroundGray" />
|
||||
|
||||
</selector>
|
||||
11
app/src/main/res/color/selector_chip_shop_text.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 24% opacity -->
|
||||
<item android:color="@color/backgroundGray" android:state_enabled="true" android:state_selected="true" />
|
||||
|
||||
<item android:color="@color/backgroundGray" android:state_checked="true" android:state_enabled="true" />
|
||||
|
||||
<item android:color="@color/chipBlack" android:state_enabled="true" />
|
||||
<item android:color="@color/chipBlack" />
|
||||
|
||||
</selector>
|
||||
60
app/src/main/res/drawable-de/buy_with_googlepay_button_content.xml
Executable file
54
app/src/main/res/drawable-fr/buy_with_googlepay_button_content.xml
Executable file
|
Before Width: | Height: | Size: 119 KiB |
BIN
app/src/main/res/drawable-hdpi/card_placeholder_wallet.9.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
54
app/src/main/res/drawable-it/buy_with_googlepay_button_content.xml
Executable file
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 54 KiB |
BIN
app/src/main/res/drawable-mdpi/card_placeholder_wallet.9.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
54
app/src/main/res/drawable-ru/buy_with_googlepay_button_content.xml
Executable file
|
Before Width: | Height: | Size: 236 KiB |
BIN
app/src/main/res/drawable-xhdpi/card_placeholder_wallet.9.png
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
app/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png
Executable file
|
After Width: | Height: | Size: 963 B |
|
After Width: | Height: | Size: 263 B |
|
Before Width: | Height: | Size: 499 KiB |
BIN
app/src/main/res/drawable-xxhdpi/card_placeholder_wallet.9.png
Normal file
|
After Width: | Height: | Size: 509 KiB |
BIN
app/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png
Executable file
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 837 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/card_placeholder_wallet.9.png
Normal file
|
After Width: | Height: | Size: 808 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/googlepay_button_background_image.9.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 819 B |
54
app/src/main/res/drawable/buy_with_googlepay_button_content.xml
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="103dp"
|
||||
android:height="17dp"
|
||||
android:viewportWidth="103.0"
|
||||
android:viewportHeight="17.0">
|
||||
<path
|
||||
android:pathData="M0.148,2.976L3.914,2.976C4.446,2.976 4.938,3.093 5.391,3.326C5.844,3.559 6.205,3.881 6.476,4.292C6.747,4.703 6.882,5.155 6.882,5.65C6.882,6.145 6.758,6.574 6.511,6.938C6.264,7.302 5.939,7.577 5.538,7.764L5.538,7.848C6.042,8.025 6.45,8.319 6.763,8.73C7.076,9.141 7.232,9.621 7.232,10.172C7.232,10.723 7.09,11.213 6.805,11.642C6.52,12.071 6.138,12.405 5.657,12.643C5.176,12.881 4.651,13 4.082,13L0.148,13L0.148,2.976ZM3.844,7.176C4.292,7.176 4.654,7.036 4.929,6.756C5.204,6.476 5.342,6.154 5.342,5.79C5.342,5.426 5.209,5.106 4.943,4.831C4.677,4.556 4.329,4.418 3.9,4.418L1.716,4.418L1.716,7.176L3.844,7.176ZM4.082,11.544C4.558,11.544 4.938,11.395 5.223,11.096C5.508,10.797 5.65,10.452 5.65,10.06C5.65,9.659 5.503,9.311 5.209,9.017C4.915,8.723 4.521,8.576 4.026,8.576L1.716,8.576L1.716,11.544L4.082,11.544ZM9.461,12.447C9.008,11.929 8.782,11.208 8.782,10.284L8.782,5.86L10.322,5.86L10.322,10.074C10.322,10.653 10.46,11.087 10.735,11.376C11.01,11.665 11.372,11.81 11.82,11.81C12.184,11.81 12.506,11.714 12.786,11.523C13.066,11.332 13.281,11.077 13.43,10.76C13.579,10.443 13.654,10.102 13.654,9.738L13.654,5.86L15.194,5.86L15.194,13L13.738,13L13.738,12.076L13.654,12.076C13.458,12.412 13.155,12.687 12.744,12.902C12.333,13.117 11.899,13.224 11.442,13.224C10.574,13.224 9.914,12.965 9.461,12.447ZM19.32,12.608L16.352,5.86L18.074,5.86L20.09,10.718L20.146,10.718L22.106,5.86L23.8,5.86L19.39,16.024L17.766,16.024L19.32,12.608ZM27.586,5.86L29.252,5.86L30.694,10.97L30.75,10.97L32.36,5.86L33.942,5.86L35.538,10.97L35.594,10.97L37.036,5.86L38.674,5.86L36.392,13L34.768,13L33.13,7.876L33.088,7.876L31.464,13L29.868,13L27.586,5.86ZM39.965,4.523C39.764,4.322 39.664,4.077 39.664,3.788C39.664,3.499 39.764,3.254 39.965,3.053C40.166,2.852 40.411,2.752 40.7,2.752C40.989,2.752 41.234,2.852 41.435,3.053C41.636,3.254 41.736,3.499 41.736,3.788C41.736,4.077 41.636,4.322 41.435,4.523C41.234,4.724 40.989,4.824 40.7,4.824C40.411,4.824 40.166,4.724 39.965,4.523ZM39.93,5.86L41.47,5.86L41.47,13L39.93,13L39.93,5.86ZM45.498,12.958C45.218,12.855 44.989,12.72 44.812,12.552C44.411,12.151 44.21,11.605 44.21,10.914L44.21,7.218L42.964,7.218L42.964,5.86L44.21,5.86L44.21,3.844L45.75,3.844L45.75,5.86L47.486,5.86L47.486,7.218L45.75,7.218L45.75,10.578C45.75,10.961 45.825,11.231 45.974,11.39C46.114,11.577 46.357,11.67 46.702,11.67C46.861,11.67 47.001,11.649 47.122,11.607C47.243,11.565 47.374,11.497 47.514,11.404L47.514,12.902C47.206,13.042 46.833,13.112 46.394,13.112C46.077,13.112 45.778,13.061 45.498,12.958ZM49.176,2.976L50.716,2.976L50.716,5.706L50.646,6.798L50.716,6.798C50.921,6.462 51.227,6.184 51.633,5.965C52.039,5.746 52.475,5.636 52.942,5.636C53.81,5.636 54.473,5.89 54.93,6.399C55.387,6.908 55.616,7.601 55.616,8.478L55.616,13L54.076,13L54.076,8.688C54.076,8.147 53.934,7.741 53.649,7.47C53.364,7.199 52.993,7.064 52.536,7.064C52.191,7.064 51.88,7.162 51.605,7.358C51.33,7.554 51.113,7.813 50.954,8.135C50.795,8.457 50.716,8.8 50.716,9.164L50.716,13L49.176,13L49.176,2.976Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M81.526,2.635L81.526,6.718L84.044,6.718C84.644,6.718 85.14,6.516 85.532,6.113C85.935,5.711 86.137,5.231 86.137,4.676C86.137,4.132 85.935,3.658 85.532,3.254C85.14,2.841 84.644,2.634 84.044,2.634L81.526,2.634L81.526,2.635ZM81.526,8.155L81.526,12.891L80.022,12.891L80.022,1.198L84.011,1.198C85.025,1.198 85.885,1.535 86.594,2.21C87.314,2.885 87.674,3.707 87.674,4.676C87.674,5.667 87.314,6.495 86.594,7.158C85.897,7.823 85.035,8.154 84.011,8.154L81.526,8.154L81.526,8.155Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M89.194,10.442C89.194,10.834 89.36,11.16 89.693,11.422C90.025,11.683 90.415,11.813 90.861,11.813C91.494,11.813 92.057,11.579 92.553,11.112C93.05,10.643 93.297,10.093 93.297,9.463C92.828,9.092 92.174,8.907 91.335,8.907C90.724,8.907 90.215,9.055 89.807,9.349C89.398,9.643 89.194,10.006 89.194,10.442M91.14,4.627C92.252,4.627 93.129,4.924 93.773,5.518C94.415,6.111 94.737,6.925 94.737,7.959L94.737,12.891L93.298,12.891L93.298,11.781L93.233,11.781C92.611,12.695 91.783,13.153 90.747,13.153C89.865,13.153 89.126,12.891 88.532,12.369C87.938,11.846 87.641,11.193 87.641,10.409C87.641,9.581 87.954,8.923 88.581,8.433C89.208,7.943 90.044,7.698 91.09,7.698C91.983,7.698 92.72,7.861 93.297,8.188L93.297,7.844C93.297,7.322 93.09,6.878 92.676,6.513C92.261,6.149 91.777,5.967 91.221,5.967C90.381,5.967 89.717,6.32 89.226,7.029L87.902,6.195C88.632,5.15 89.711,4.627 91.14,4.627"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M102.993,4.889l-5.02,11.531l-1.553,0l1.864,-4.035l-3.303,-7.496l1.635,0l2.387,5.749l0.033,0l2.322,-5.749z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M75.448,7.134C75.448,6.661 75.408,6.205 75.332,5.768L68.988,5.768L68.988,8.356L72.622,8.356C72.466,9.199 71.994,9.917 71.278,10.398L71.278,12.079L73.447,12.079C74.716,10.908 75.448,9.179 75.448,7.134"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#4285F4"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M68.988,13.701C70.804,13.701 72.332,13.105 73.447,12.079L71.278,10.398C70.675,10.804 69.897,11.041 68.988,11.041C67.234,11.041 65.744,9.859 65.212,8.267L62.978,8.267L62.978,9.998C64.085,12.193 66.36,13.701 68.988,13.701"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#34A853"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M65.212,8.267C65.076,7.861 65.001,7.428 65.001,6.981C65.001,6.534 65.076,6.101 65.212,5.695L65.212,3.964L62.978,3.964C62.52,4.871 62.261,5.896 62.261,6.981C62.261,8.066 62.52,9.091 62.978,9.998L65.212,8.267Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FABB05"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M68.988,2.921C69.98,2.921 70.868,3.262 71.569,3.929L71.569,3.93L73.489,2.012C72.323,0.928 70.803,0.261 68.988,0.261C66.36,0.261 64.085,1.769 62.978,3.964L65.212,5.695C65.744,4.103 67.234,2.921 68.988,2.921"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#E94235"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
||||
6
app/src/main/res/drawable/googlepay_button_background.xml
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item
|
||||
android:drawable="@drawable/googlepay_button_background_image" />
|
||||
</selector>
|
||||
|
||||
48
app/src/main/res/drawable/googlepay_button_content.xml
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="41dp"
|
||||
android:height="17dp"
|
||||
android:viewportWidth="41.0"
|
||||
android:viewportHeight="17.0">
|
||||
<path
|
||||
android:pathData="M19.526,2.635L19.526,6.718L22.044,6.718C22.644,6.718 23.14,6.516 23.532,6.113C23.935,5.711 24.137,5.231 24.137,4.676C24.137,4.132 23.935,3.658 23.532,3.254C23.14,2.841 22.644,2.634 22.044,2.634L19.526,2.634L19.526,2.635ZM19.526,8.155L19.526,12.891L18.022,12.891L18.022,1.198L22.011,1.198C23.025,1.198 23.885,1.535 24.594,2.21C25.314,2.885 25.674,3.707 25.674,4.676C25.674,5.667 25.314,6.495 24.594,7.158C23.897,7.823 23.035,8.154 22.011,8.154L19.526,8.154L19.526,8.155Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M27.194,10.442C27.194,10.834 27.36,11.16 27.693,11.422C28.025,11.683 28.415,11.813 28.861,11.813C29.494,11.813 30.057,11.579 30.553,11.112C31.05,10.643 31.297,10.093 31.297,9.463C30.828,9.092 30.174,8.907 29.335,8.907C28.724,8.907 28.215,9.055 27.807,9.349C27.398,9.643 27.194,10.006 27.194,10.442M29.14,4.627C30.252,4.627 31.129,4.924 31.773,5.518C32.415,6.111 32.737,6.925 32.737,7.959L32.737,12.891L31.298,12.891L31.298,11.781L31.233,11.781C30.611,12.695 29.783,13.153 28.747,13.153C27.865,13.153 27.126,12.891 26.532,12.369C25.938,11.846 25.641,11.193 25.641,10.409C25.641,9.581 25.954,8.923 26.581,8.433C27.208,7.943 28.044,7.698 29.09,7.698C29.983,7.698 30.72,7.861 31.297,8.188L31.297,7.844C31.297,7.322 31.09,6.878 30.676,6.513C30.261,6.149 29.777,5.967 29.221,5.967C28.381,5.967 27.717,6.32 27.226,7.029L25.902,6.195C26.632,5.15 27.711,4.627 29.14,4.627"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M40.993,4.889l-5.02,11.531l-1.553,0l1.864,-4.035l-3.303,-7.496l1.635,0l2.387,5.749l0.033,0l2.322,-5.749z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M13.448,7.134C13.448,6.661 13.408,6.205 13.332,5.768L6.988,5.768L6.988,8.356L10.622,8.356C10.466,9.199 9.994,9.917 9.278,10.398L9.278,12.079L11.447,12.079C12.716,10.908 13.448,9.179 13.448,7.134"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#4285F4"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M6.988,13.701C8.804,13.701 10.332,13.105 11.447,12.079L9.278,10.398C8.675,10.804 7.897,11.041 6.988,11.041C5.234,11.041 3.744,9.859 3.212,8.267L0.978,8.267L0.978,9.998C2.085,12.193 4.36,13.701 6.988,13.701"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#34A853"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M3.212,8.267C3.076,7.861 3.001,7.428 3.001,6.981C3.001,6.534 3.076,6.101 3.212,5.695L3.212,3.964L0.978,3.964C0.52,4.871 0.261,5.896 0.261,6.981C0.261,8.066 0.52,9.091 0.978,9.998L3.212,8.267Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FABB05"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:pathData="M6.988,2.921C7.98,2.921 8.868,3.262 9.569,3.929L9.569,3.93L11.489,2.012C10.323,0.928 8.803,0.261 6.988,0.261C4.36,0.261 2.085,1.769 0.978,3.964L3.212,5.695C3.744,4.103 5.234,2.921 6.988,2.921"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#E94235"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
||||
6
app/src/main/res/drawable/googlepay_button_no_shadow_background.xml
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item
|
||||
android:drawable="@drawable/googlepay_button_no_shadow_background_image" />
|
||||
</selector>
|
||||
|
||||
12
app/src/main/res/drawable/googlepay_button_overlay.xml
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_enabled="false">
|
||||
<shape
|
||||
android:shape="rectangle" >
|
||||
<corners android:radius="4dp"/>
|
||||
<solid android:color="#7FFFFFFF"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:drawable="@android:color/transparent" />
|
||||
</selector>
|
||||
|
||||
5
app/src/main/res/drawable/ic_clear_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="@color/iconGray" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<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>
|
||||
11
app/src/main/res/drawable/ic_promo_code.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<vector android:autoMirrored="true" android:height="20dp"
|
||||
android:viewportHeight="20" android:viewportWidth="20"
|
||||
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group>
|
||||
<clip-path android:pathData="M0,0h20v20h-20z"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M17.2412,14.1916L17.2412,11.7284C16.8163,11.6812 16.4151,11.516 16.0847,11.1855C15.3295,10.4303 15.3531,9.2266 16.0847,8.495C16.4151,8.1646 16.8163,7.9994 17.2412,7.9522L17.2412,5.4889C17.2412,5.1585 16.958,4.8753 16.6275,4.8753L3.4197,4.8281C3.0893,4.8281 2.806,5.1113 2.806,5.4417L2.806,7.905C3.2309,7.9522 3.6793,8.1174 4.0097,8.4478C4.7649,9.203 4.7413,10.4067 4.0097,11.1383C3.6793,11.4688 3.2545,11.6576 2.806,11.6812L2.806,14.1444C2.806,14.4748 3.0893,14.7581 3.4197,14.7581L16.6275,14.7581C16.958,14.8053 17.2412,14.522 17.2412,14.1916Z"
|
||||
android:strokeColor="#090E13" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="1.1"/>
|
||||
</group>
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_shipping.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<vector android:autoMirrored="true" android:height="20dp"
|
||||
android:viewportHeight="20" android:viewportWidth="20"
|
||||
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M2.4,6H14.4V17.2H2.4V6ZM17.6,2.8L14.4,6H2.4L6.5852,2.8H17.6Z"
|
||||
android:strokeColor="#000000" android:strokeLineJoin="round" android:strokeWidth="1.1"/>
|
||||
<path android:fillColor="#00000000"
|
||||
android:pathData="M8.4,6L12,2.8M17.6,13.2L14.4,17.2V6L17.6,2.8V13.2ZM6.4,8.4H10.4H6.4Z"
|
||||
android:strokeColor="#000000" android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" android:strokeWidth="1.1"/>
|
||||
</vector>
|
||||
8
app/src/main/res/drawable/shape_line.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="line">
|
||||
<stroke android:width="1dp" android:color="@color/darkGray6"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
8
app/src/main/res/drawable/shape_rectangle_rounded_4.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<solid android:color="@color/backgroundGray" />
|
||||
|
||||
<corners android:radius="4dp" />
|
||||
|
||||
</shape>
|
||||
31
app/src/main/res/layout/buy_with_googlepay_button.xml
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48sp"
|
||||
android:background="@drawable/googlepay_button_no_shadow_background"
|
||||
android:padding="2sp"
|
||||
android:contentDescription="@string/buy_with_googlepay_button_content_description">
|
||||
<LinearLayout
|
||||
android:duplicateParentState="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:weightSum="2"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
<ImageView
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:duplicateParentState="true"
|
||||
android:src="@drawable/buy_with_googlepay_button_content"/>
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitXY"
|
||||
android:duplicateParentState="true"
|
||||
android:src="@drawable/googlepay_button_overlay"/>
|
||||
</RelativeLayout>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/pseudo_toolbar" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_recieve_message"
|
||||
android:id="@+id/tv_receive_message"
|
||||
style="@style/TextViewOnboarding.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
android:layout_height="?attr/actionBarSize"
|
||||
app:menu="@menu/popular_tokens"
|
||||
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
|
||||
app:title="Add tokens" />
|
||||
app:title="@string/add_tokens_title" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
android:layout_marginBottom="16dp"
|
||||
android:enabled="false"
|
||||
android:gravity="center"
|
||||
android:text="Save changes"
|
||||
android:text="@string/common_save_changes"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
|
|
|||
|
|
@ -133,32 +133,39 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/tv_issuer"
|
||||
tools:text="48 hashes" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_security"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="15dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:textColor="@color/darkGray1"
|
||||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
|
||||
app:drawableTint="@color/darkGray1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes_title"
|
||||
tools:text="Long Tap" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_security_title"
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll_manage_security"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:text="@string/details_row_title_manage_security"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_signed_hashes_title">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_security_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/details_row_title_manage_security"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_security"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="15dp"
|
||||
android:gravity="end"
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/darkGray1"
|
||||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
|
||||
app:drawableTint="@color/darkGray1"
|
||||
tools:text="Long Tap" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_create_backup"
|
||||
|
|
@ -173,7 +180,7 @@
|
|||
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
|
||||
app:drawableTint="@color/darkGray1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
|
||||
app:layout_constraintTop_toBottomOf="@id/ll_manage_security" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reset_to_factory"
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
android:id="@+id/tv_warning"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Warning"
|
||||
android:text="@string/common_warning"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="32sp"
|
||||
android:layout_marginTop="32dp"
|
||||
|
|
@ -80,11 +80,11 @@
|
|||
android:id="@+id/btn_confirm"
|
||||
style="@style/TapBlackButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="7dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
tools:text="@string/common_save"
|
||||
tools:text="@string/details_row_title_reset_factory_settings"
|
||||
tools:icon="@drawable/ic_send"
|
||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
|
||||
app:title="@string/details_row_title_manage_security" />
|
||||
app:title="@string/details_manage_security_title" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/card_placeholder_new"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:visibility="gone"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/card_placeholder_new"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:scaleType="fitCenter"
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/card_placeholder_new"
|
||||
android:src="@drawable/card_placeholder_black"
|
||||
android:transitionName="imv_front_card"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
|
|
|
|||
375
app/src/main/res/layout/fragment_shop.xml
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/coordinator_details_confirm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/backgroundLightGray"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fitsSystemWindows="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
style="@style/ThemeOverlay.MyTheme.Toolbar.AccentColorMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/backgroundLightGray"
|
||||
android:fitsSystemWindows="true"
|
||||
app:liftOnScroll="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:navigationIcon="@drawable/ic_clear_24"
|
||||
app:title="@string/shop_title"
|
||||
app:titleCentered="true" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom"
|
||||
android:clickable="true"
|
||||
android:fitsSystemWindows="true"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_cards"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="36dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="36dp"
|
||||
android:layout_weight="1"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tv_header"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imv_third"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/card_placeholder_wallet"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_header"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="@color/darkGray2" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imv_second"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/card_placeholder_wallet"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_header"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="@color/darkGray4" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imv_first"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/card_placeholder_wallet"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_header"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="44dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/shop_one_wallet"
|
||||
android:textColor="#060606"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/chip_group_product"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/fl_cards" />
|
||||
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/chip_group_product"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:background="@drawable/shape_rectangle_rounded_100"
|
||||
android:backgroundTint="@color/backgroundGray"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingEnd="3dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:selectionRequired="true"
|
||||
app:singleLine="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_product_1"
|
||||
style="@style/ShopChips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:checked="true"
|
||||
android:text="@string/shop_3_cards"
|
||||
app:chipMinTouchTargetSize="0dp" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_product_2"
|
||||
style="@style/ShopChips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:checked="false"
|
||||
android:text="@string/shop_2_cards"
|
||||
app:chipMinTouchTargetSize="0dp" />
|
||||
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
<View
|
||||
android:id="@+id/v_shipping_discount_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="93dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@drawable/shape_rectangle_rounded_4"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_total_background" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_delivery"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:src="@drawable/ic_shipping"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_divider"
|
||||
app:layout_constraintStart_toStartOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_shipping_discount_background" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_delivery_worldwide"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:text="@string/shop_shipping"
|
||||
android:textColor="@color/textBlack"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_divider"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_delivery"
|
||||
app:layout_constraintTop_toTopOf="@id/v_shipping_discount_background" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_delivery_cost"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="@string/shop_free"
|
||||
android:textColor="@color/textBlack"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/v_divider"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_shipping_discount_background" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_divider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#BEBEBE"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintStart_toStartOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_shipping_discount_background" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_promo_code"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:src="@drawable/ic_promo_code"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintStart_toStartOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintTop_toBottomOf="@id/v_divider" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_promo_code"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:hint="@string/shop_i_have_a_promo_code"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textCapCharacters"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/textBlack"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_promo_code"
|
||||
app:layout_constraintTop_toBottomOf="@id/v_divider" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_promo_code"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:indeterminateTint="@color/darkGray2"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_shipping_discount_background"
|
||||
app:layout_constraintTop_toBottomOf="@id/v_divider" />
|
||||
|
||||
|
||||
<View
|
||||
android:id="@+id/v_total_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="21dp"
|
||||
android:background="@drawable/shape_rectangle_rounded_4"
|
||||
app:layout_constraintBottom_toTopOf="@id/ll_buttons" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_total_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="@string/shop_total"
|
||||
android:textColor="@color/textBlack"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_total_background"
|
||||
app:layout_constraintStart_toStartOf="@id/v_total_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_total_background" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_total_before_discount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="@drawable/shape_line"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_total_background"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_total"
|
||||
app:layout_constraintTop_toTopOf="@id/v_total_background"
|
||||
tools:text="$44.20" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_total_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_total_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_total_background"
|
||||
tools:text="$44.20" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_price"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:indeterminateTint="@color/darkGray2"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_total_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/v_total_background"
|
||||
app:layout_constraintTop_toTopOf="@id/v_total_background" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<include
|
||||
android:id="@+id/btn_pay_google_pay"
|
||||
layout="@layout/buy_with_googlepay_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48sp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_main_action"
|
||||
style="@style/TapBlackButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48sp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginBottom="70dp"
|
||||
android:text="@string/shop_buy_now"
|
||||
android:textAlignment="center"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_alternative_payment"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="42dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:paddingTop="0dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:text="@string/shop_other_payment_methods"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/textBlack"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_add_token"
|
||||
android:layout_width="102dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="43dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:backgroundTint="@color/selector_btn_green"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="24dp">
|
||||
android:layout_height="120dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_amount"
|
||||
|
|
@ -48,12 +47,13 @@
|
|||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/shape_circle"/>
|
||||
tools:src="@drawable/shape_circle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_token_letter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
|
|
@ -61,8 +61,7 @@
|
|||
app:layout_constraintEnd_toEndOf="@id/iv_currency"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_currency"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_currency"
|
||||
android:layout_marginBottom="2dp"
|
||||
tools:text="J"/>
|
||||
tools:text="J" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_status_verified"
|
||||
|
|
@ -131,6 +130,4 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_fiat_amount" />
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -71,19 +71,15 @@
|
|||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_qr_code"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitXY"
|
||||
android:scaleType="fitStart"
|
||||
app:layout_constraintEnd_toEndOf="@id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/chip_group_address_type"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_qr_lower_end"
|
||||
tools:src="@drawable/ic_qr_code_show" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
|
|
@ -92,22 +88,20 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintGuide_percent="0.4" />
|
||||
app:layout_constraintGuide_percent="0.40" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_address"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:ellipsize="middle"
|
||||
android:textColor="@color/darkGray1"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_qr_code"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_qr_code"
|
||||
tools:text="139mrsJgyWnJjkljlkhiuojlkljkjljljlkjlkfsdkdsjflsdkjflsdkjfffffffljlkjkljlkjlkjkljky9BV"
|
||||
android:singleLine="true" />
|
||||
tools:text="139mrsJgyWnJjkljlkhiuojlkljkjljljlkjlkfsdkdsjflsdkjflsdkjfffffffljlkjkljlkjlkjkljky9BV" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_explore"
|
||||
|
|
@ -126,72 +120,60 @@
|
|||
app:layout_constraintStart_toEndOf="@id/iv_qr_code"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_address" />
|
||||
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/btn_copy"
|
||||
style="@style/Widget.MaterialComponents.Chip.Action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:src="@drawable/ic_inactive"
|
||||
android:text="@string/wallet_address_button_copy"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/colorSecondary"
|
||||
app:chipBackgroundColor="@color/blue_pale"
|
||||
app:chipIcon="@drawable/ic_copy_chip"
|
||||
app:iconStartPadding="12dp"
|
||||
app:iconEndPadding="0dp"
|
||||
app:chipIconSize="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_explore"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_share"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_qr_code" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_qr_lower_end"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_copy"
|
||||
app:layout_constraintStart_toStartOf="@id/btn_copy"
|
||||
android:layout_marginTop="5dp"
|
||||
/>
|
||||
|
||||
app:iconEndPadding="0dp"
|
||||
app:iconStartPadding="12dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_share"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iv_qr_code" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/btn_share"
|
||||
style="@style/Widget.MaterialComponents.Chip.Action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:src="@drawable/ic_inactive"
|
||||
android:text="@string/wallet_address_button_share"
|
||||
app:chipIcon="@drawable/ic_share_chip"
|
||||
app:iconStartPadding="12dp"
|
||||
app:iconEndPadding="0dp"
|
||||
app:chipIconSize="16dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/colorSecondary"
|
||||
app:chipBackgroundColor="@color/blue_pale"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_explore"
|
||||
app:chipIcon="@drawable/ic_share_chip"
|
||||
app:chipIconSize="16dp"
|
||||
app:iconEndPadding="0dp"
|
||||
app:iconStartPadding="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/btn_copy" />
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/btn_copy"
|
||||
app:layout_constraintTop_toTopOf="@+id/btn_copy" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_recieve_message"
|
||||
android:id="@+id/tv_receive_message"
|
||||
style="@style/TextViewOnboarding.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iv_qr_code"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_copy"
|
||||
tools:text="@string/address_qr_code_message_token_format" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
android:layout_marginBottom="33dp"
|
||||
android:drawableTop="@drawable/ic_group_1243"
|
||||
android:gravity="bottom|center_horizontal"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:text="@string/wallet_button_scan"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_trade"
|
||||
|
|
|
|||
87
app/src/main/res/layout/test_shopify_fragment.xml
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?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">
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_2_cards"
|
||||
style="@style/TapButton"
|
||||
android:text="2 cards"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_3_cards"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_margin="16dp"/>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_3_cards"
|
||||
style="@style/TapButton"
|
||||
android:text="3 cards"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/btn_2_cards"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_promo_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:hint="Promo Code"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:textAlignment="center"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_price"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||
android:text="1.00 USD"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_total"
|
||||
android:textAlignment="center"
|
||||
android:padding="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_total"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||
android:text="1.00 USD"
|
||||
app:layout_constraintBottom_toTopOf="@id/pay_gpay"
|
||||
android:textAlignment="center"
|
||||
android:padding="16dp"/>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/pay_gpay"
|
||||
style="@style/TapButton"
|
||||
android:text="GPay"
|
||||
app:layout_constraintEnd_toStartOf="@+id/pay_web"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_margin="16dp"/>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/pay_web"
|
||||
style="@style/TapButton"
|
||||
android:text="Pay online"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/pay_gpay"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
<string name="common_cancel"> Annuler </string>
|
||||
<string name="common_accept">J\'accepte</string>
|
||||
|
||||
<string name="common_camera_denied_alert_title">L’accès à la caméra est refusé </string>
|
||||
<string name="common_camera_denied_alert_message">Vous n\'avez pas octroyé l’accès à votre caméra, veuillez modifier vos paramètres de confidentialité </string>
|
||||
<string name="common_camera_denied_alert_title">L\'accès à la caméra est refusé </string>
|
||||
<string name="common_camera_denied_alert_message">Vous n\'avez pas octroyé l\'accès à votre caméra, veuillez modifier vos paramètres de confidentialité </string>
|
||||
<string name="common_camera_alert_button_settings">Paramètres </string>
|
||||
<string name="home_welcome">Bienvenue à Tangem. Avez-vous une de nos cartes</string>
|
||||
<string name="home_welcome_back"> Encore une fois, bienvenue dans Tangem. \nScannez votre carte pour commencer.</string>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
<string name="wallet_balance_verified">Solde confirmé </string>
|
||||
<string name="wallet_balance_loading"> Solde est en cours de téléchargement …</string>
|
||||
<string name="wallet_balance_blockchain_unreachable">Blockchain est inaccessible </string>
|
||||
<string name="wallet_error_no_account">Compte n’est pas créé </string>
|
||||
<string name="wallet_error_no_account">Compte n\'est pas créé </string>
|
||||
<string name="wallet_error_no_account_subtitle_format"> Téléchargez %s +%s pour créer un compte </string>
|
||||
<string name="wallet_error_empty_card">Carte vide </string>
|
||||
<string name="wallet_error_empty_card_subtitle">Créez un portefeuille pour commencer à utiliser votre carte Tangem </string>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<string name="wallet_error_unsupported_blockchain_subtitle">Votre carte Tangem a été créée pour fonctionner avec une autre application. Regardez le nom et les instructions sur votre carte et installez l\'application pertinente </string>
|
||||
<string name="wallet_balance_tx_in_progress">Transaction en cours…</string>
|
||||
<string name="wallet_pending_tx_sending">Envoi\u0020</string>
|
||||
<string name="wallet_pending_tx_sending_address_format">jusqu’à %s </string>
|
||||
<string name="wallet_pending_tx_sending_address_format">jusqu\'à %s </string>
|
||||
<string name="wallet_pending_tx_receiving">Réception \u0020</string>
|
||||
<string name="wallet_pending_tx_receiving_address_format">de %s </string>
|
||||
<string name="wallet_address_button_explore">Explorer l\'adresse </string>
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
<string name="details_row_title_issuer">Emetteur </string>
|
||||
<string name="details_row_title_signed_hashes">Signé </string>
|
||||
<string name="details_row_subtitle_signed_hashes_format">%s hashes </string>
|
||||
<string name="details_row_title_currency">Monnaie de l’application </string>
|
||||
<string name="details_row_title_currency">Monnaie de l\'application </string>
|
||||
<string name="details_section_title_settings">Paramètres </string>
|
||||
<string name="details_section_title_card">Carte </string>
|
||||
<string name="details_row_title_validate">Valider la carte </string>
|
||||
|
|
@ -93,9 +93,9 @@
|
|||
<string name="details_manage_security_long_tap_description">Ce mécanisme protège contre les attaques sans contact sur la carte. Il y a un délai entre la réception et l\'exécution de la commande. Après la première transaction signée, ce téléphone sera associé à la carte et les transactions seront signées immédiatement.</string>
|
||||
<string name="details_manage_security_passcode">Mot de passe </string>
|
||||
<string name="details_manage_security_passcode_description">Avant d\'exécuter une commande qui modifie l\'état de la carte, vous devrez entrer un mot de passe.</string>
|
||||
<string name="details_manage_security_access_code">Code d’accès </string>
|
||||
<string name="details_manage_security_access_code">Code d\'accès </string>
|
||||
<string name="details_manage_security_access_code_description">Vous devrez entrer le mot de passe correct avant de scanner la carte </string>
|
||||
<string name="alert_old_device_this_card">Vous pouvez rencontrer des problèmes NFC avec certains iPhone 7/7 + lors de l’extraction </string>
|
||||
<string name="alert_old_device_this_card">Vous pouvez rencontrer des problèmes NFC avec certains iPhone 7/7 + lors de l\'extraction </string>
|
||||
<string name="alert_card_signed_transactions">Cette carte a déjà été rechargée et a signé des transactions avant. Envisagez la possibilité de retirer tous les fonds immédiatement si vous avez reçu cette carte d\'une source non fiable.</string>
|
||||
<string name="alert_title">Attention</string>
|
||||
<string name="alert_unsupported_card">Cette carte n\'est pas conçue pour fonctionner avec Tangem</string>
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
<string name="initial_message_sign_body">Appuyez votre carte au téléphone comme indiqué ci-dessus </string>
|
||||
<string name="initial_message_purge_wallet_body">Touchez, pour annuler un portefeuille </string>
|
||||
<string name="initial_message_create_wallet_body">Touchez, pour créer un portefeuille </string>
|
||||
<string name="initial_message_change_access_code_body">Touchez, pour modifier le code d’accès </string>
|
||||
<string name="initial_message_change_access_code_body">Touchez, pour modifier le code d\'accès </string>
|
||||
<string name="initial_message_change_passcode_body">Touchez, pour modifier le mot de passe </string>
|
||||
<string name="payid_service_error_loading">PayString incorrect </string>
|
||||
|
||||
|
|
@ -115,44 +115,44 @@ Avertissement
|
|||
|
||||
\n\n1.Application Tangem (Logiciel)
|
||||
|
||||
\n\nLe logiciel est destiné à l\’utilisation exclusivement avec les e-portefeuilles Tangem (Cartes) à l\’aide de l\’interface NFC. Le logiciel NE réalise pas ce qui suit :
|
||||
\n\nLe logiciel est destiné à l\'utilisation exclusivement avec les e-portefeuilles Tangem (Cartes) à l\'aide de l\'interface NFC. Le logiciel NE réalise pas ce qui suit :
|
||||
|
||||
\n\na. Génération, stockage, transmission ou octroi d\’accès aux clés privées (confidentiels) de chiffrement des blockchain-portefeuilles, qui contiennent les avoirs numériques, y compris la crypto-monnaie.
|
||||
\n\nb. Génération, stockage, transmission ou octroi d\’accès aux clés confidentielles, aux mots de passe, phrases secrètes, phrases de restitution, qui pourront être utilisées pour la restitution ou pour le clonage des clés privées (confidentiels) de chiffrement des blockchain-portefeuilles, contenant les avoirs numériques, y compris la crypto-monnaie.
|
||||
\n\nc. Prestation des services de bourse, de commerce, d\’investissement du nom de Tangem AG.
|
||||
\n\na. Génération, stockage, transmission ou octroi d\'accès aux clés privées (confidentiels) de chiffrement des blockchain-portefeuilles, qui contiennent les avoirs numériques, y compris la crypto-monnaie.
|
||||
\n\nb. Génération, stockage, transmission ou octroi d\'accès aux clés confidentielles, aux mots de passe, phrases secrètes, phrases de restitution, qui pourront être utilisées pour la restitution ou pour le clonage des clés privées (confidentiels) de chiffrement des blockchain-portefeuilles, contenant les avoirs numériques, y compris la crypto-monnaie.
|
||||
\n\nc. Prestation des services de bourse, de commerce, d\'investissement du nom de Tangem AG.
|
||||
|
||||
|
||||
\n\n2. Risques, liés avec l\’utilisation du logiciel
|
||||
\n\n2. Risques, liés avec l\'utilisation du logiciel
|
||||
|
||||
\n\nTangem n\’assume aucune responsabilité pour tous les dommages, préjudice ou prétentions, qui peuvent survenir comme résultat des évènements, se rapportant à une de cinq catégories suivantes :
|
||||
\n\nTangem n\'assume aucune responsabilité pour tous les dommages, préjudice ou prétentions, qui peuvent survenir comme résultat des évènements, se rapportant à une de cinq catégories suivantes :
|
||||
|
||||
|
||||
\n\na. Les erreurs, commises par l\’utilisateur de tout logiciel ou service liés avec la crypto-monnaie, par exemple, les mots de passe oubliés, les paiements envoyés aux adresses incorrectes, et élimination occasionnelle des blockchain-portefeuilles sur les Cartes.
|
||||
\n\nb. Les problèmes du Logiciel et/ou de tout progiciel ou service liés avec blockchain ou avec la crypto-monnaie, par exemple, les fichiers endommagés, les transaction créées d\’une manière incorrecte, les bibliothèques cryptographiques non sécurisées, les logiciels malveillants.
|
||||
\n\nc. Les défaillances techniques du hardware de l\’utilisateur, y compris les Cartes, de tout logiciel ou service liés avec la crypto-monnaie, par exemple, la perte des données à cause des périphériques défectives ou endommagées de stockage.
|
||||
\n\nd. Les problèmes de la sécurité, subis par l\’utilisateur de tout logiciel ou service liés avec la crypto-monnaie, par exemple, l\’accès non autorisé aux portefeuilles et/ou comptes des utilisateurs.
|
||||
\n\ne. Les actions ou l\’inaction des tierces personnes et/ou les évènements subis par les tierces personnes, par exemple, la faillite du prestataire de services, les attaques sur la sécurité informatique des prestataires de services et la fraude commise par des tierces personnes.
|
||||
\n\na. Les erreurs, commises par l\'utilisateur de tout logiciel ou service liés avec la crypto-monnaie, par exemple, les mots de passe oubliés, les paiements envoyés aux adresses incorrectes, et élimination occasionnelle des blockchain-portefeuilles sur les Cartes.
|
||||
\n\nb. Les problèmes du Logiciel et/ou de tout progiciel ou service liés avec blockchain ou avec la crypto-monnaie, par exemple, les fichiers endommagés, les transaction créées d\'une manière incorrecte, les bibliothèques cryptographiques non sécurisées, les logiciels malveillants.
|
||||
\n\nc. Les défaillances techniques du hardware de l\'utilisateur, y compris les Cartes, de tout logiciel ou service liés avec la crypto-monnaie, par exemple, la perte des données à cause des périphériques défectives ou endommagées de stockage.
|
||||
\n\nd. Les problèmes de la sécurité, subis par l\'utilisateur de tout logiciel ou service liés avec la crypto-monnaie, par exemple, l\'accès non autorisé aux portefeuilles et/ou comptes des utilisateurs.
|
||||
\n\ne. Les actions ou l\'inaction des tierces personnes et/ou les évènements subis par les tierces personnes, par exemple, la faillite du prestataire de services, les attaques sur la sécurité informatique des prestataires de services et la fraude commise par des tierces personnes.
|
||||
|
||||
\n\n3. Risques commerciales et d\’investissement
|
||||
\n\n3. Risques commerciales et d\'investissement
|
||||
|
||||
\n\nToute échange de crypto-monnaie ou d\’autres avoirs numériques implique les risques importants. Toute transaction liée avec la monnaie implique les risques, qui incluent, entre autres, la possibilité de modification des conditions économiques, qui peuvent influencer d\’une manière significative le prix ou la disponibilité de la monnaie. Les investissements dans les spéculations boursières avec les crypto-monnaies peuvent aussi être exposés aux montées et chutes en flèche lors des fluctuations des valeurs marchandes correspondants. C\'est pour cette raison, que lors de la spéculation sur tels marchés, il est conseillé d\’utiliser seulement le capital-risque.
|
||||
\n\nToute échange de crypto-monnaie ou d\'autres avoirs numériques implique les risques importants. Toute transaction liée avec la monnaie implique les risques, qui incluent, entre autres, la possibilité de modification des conditions économiques, qui peuvent influencer d\'une manière significative le prix ou la disponibilité de la monnaie. Les investissements dans les spéculations boursières avec les crypto-monnaies peuvent aussi être exposés aux montées et chutes en flèche lors des fluctuations des valeurs marchandes correspondants. C\'est pour cette raison, que lors de la spéculation sur tels marchés, il est conseillé d\'utiliser seulement le capital-risque.
|
||||
|
||||
|
||||
\n\n4. Risques de commerce électronique
|
||||
|
||||
\n\nAvant de passer aux transactions en utilisant le système électronique, Vous devez prendre connaissance, d\’une manière bien attentive, des règles et des dispositions stipulées par les bourses qui offrent ce système, et/ou les listes des titres de placement que vous voulez négocier. Le commerce en ligne possède le risque inaliénable lié avec la vitesse de réponse du système et avec le temps d\’accès qui peuvent varier en fonction des conditions de marché, du rendement du système et d\’autres facteurs. Avant de commencer les négoces, vous devez comprendre ces risques aussi que les risques supplémentaires.
|
||||
\n\nAvant de passer aux transactions en utilisant le système électronique, Vous devez prendre connaissance, d\'une manière bien attentive, des règles et des dispositions stipulées par les bourses qui offrent ce système, et/ou les listes des titres de placement que vous voulez négocier. Le commerce en ligne possède le risque inaliénable lié avec la vitesse de réponse du système et avec le temps d\'accès qui peuvent varier en fonction des conditions de marché, du rendement du système et d\'autres facteurs. Avant de commencer les négoces, vous devez comprendre ces risques aussi que les risques supplémentaires.
|
||||
|
||||
\n\n5. Respect des obligations fiscales
|
||||
|
||||
\n\nLes utilisateurs du Logiciel assument toute la responsabilité pour définir, quels impôts sont appliqués à leurs transactions avec la crypto-monnaie, au cas où il y a de tels impôts. Les propriétaires et les participants à l\’élaboration du Logiciel n\’assument pas la responsabilité pour la définition des impôts qui sont appliqués aux transactions avec la crypto-monnaie.
|
||||
\n\nLes utilisateurs du Logiciel assument toute la responsabilité pour définir, quels impôts sont appliqués à leurs transactions avec la crypto-monnaie, au cas où il y a de tels impôts. Les propriétaires et les participants à l\'élaboration du Logiciel n\'assument pas la responsabilité pour la définition des impôts qui sont appliqués aux transactions avec la crypto-monnaie.
|
||||
|
||||
\n\n6. Absence de garanties
|
||||
|
||||
\n\nLe logiciel est concédé sous les conditions « tel quel », sans aucune garantie à l\’égard du Logiciel et/ou de tout le contenu, données, matériaux et/ou services, présentes dans ce Logiciel.
|
||||
\n\nLe logiciel est concédé sous les conditions « tel quel », sans aucune garantie à l\'égard du Logiciel et/ou de tout le contenu, données, matériaux et/ou services, présentes dans ce Logiciel.
|
||||
|
||||
\n\n7. Restriction de la responsabilité
|
||||
|
||||
\n\nSauf disposition contraire prévue par la législation, les propriétaires et les participants à l\’élaboration du Logiciel n\’assument pas la responsabilité pour aucun dommage, y compris l\’indisponibilité, la perte de profit ou la perte des données, qui surviennent comme résultat de l\’utilisation ou bien qui sont liés d\’une certaine manière avec l\’utilisation du Logiciel. Les propriétaires et les participants à l\’élaboration du Logiciel n\’assument pas la responsabilité pour les actions, les résolutions ou pour une autre conduite que vous manifestez ou pas par l\’intermédiaire du Logiciel.
|
||||
\n\nSauf disposition contraire prévue par la législation, les propriétaires et les participants à l\'élaboration du Logiciel n\'assument pas la responsabilité pour aucun dommage, y compris l\'indisponibilité, la perte de profit ou la perte des données, qui surviennent comme résultat de l\'utilisation ou bien qui sont liés d\'une certaine manière avec l\'utilisation du Logiciel. Les propriétaires et les participants à l\'élaboration du Logiciel n\'assument pas la responsabilité pour les actions, les résolutions ou pour une autre conduite que vous manifestez ou pas par l\'intermédiaire du Logiciel.
|
||||
|
||||
|
||||
\n\n8. Dernière modification
|
||||
|
|
@ -171,14 +171,14 @@ Avertissement
|
|||
<string name="send_error_payid_unsupported_by_blockchain">PayString non pris en charge par la blockchain</string>
|
||||
<string name="send_error_payid_not_registered">PayString non enregistré</string>
|
||||
<string name="send_error_payid_request_failed">La demande de PayString a échoué</string>
|
||||
<string name="send_error_address_same_as_wallet">L’adresse est la même que celle de votre portefeuille</string>
|
||||
<string name="send_error_address_same_as_wallet">L\'adresse 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">L’adresse a été copiée avec succès</string>
|
||||
<string name="wallet_create_payid_empty">Saisissez d’abord le PayString requis</string>
|
||||
<string name="wallet_notification_address_copied">L\'adresse a été copiée avec succès</string>
|
||||
<string name="wallet_create_payid_empty">Saisissez d\'abord le PayString 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>
|
||||
|
|
|
|||
379
app/src/main/res/values-ru/strings.xml
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Tangem</string>
|
||||
<string name="common_no">Нет</string>
|
||||
<string name="common_save_changes">Сохранить изменения</string>
|
||||
<string name="common_warning">Предупреждение</string>
|
||||
<string name="common_retry">Повторить попытку</string>
|
||||
<string name="common_done">Готово</string>
|
||||
<string name="common_cancel">Отмена</string>
|
||||
<string name="common_accept">Принять</string>
|
||||
<string name="common_custom_string">%s</string>
|
||||
<string name="common_camera_denied_alert_title">Доступ к камере запрещен</string>
|
||||
<string name="common_camera_denied_alert_message">Вы не предоставили доступ к своей камере, измените настройки конфиденциальности.</string>
|
||||
<string name="common_camera_alert_button_settings">Настройки</string>
|
||||
<string name="home_welcome">Добро пожаловать в Tangem.\nУ Вас есть одна из наших карт?</string>
|
||||
<string name="home_welcome_back">Добро пожаловать обратно в Тангем. \nОтсканируйте карту, чтобы начать.</string>
|
||||
<string name="home_button_shop">Магазин</string>
|
||||
<string name="home_ready_title">Приготовьтесь приложить свою\nкарту к задней панели\nтелефона.</string>
|
||||
<string name="home_button_tapin">Нажмите на</string>
|
||||
<string name="home_button_scan">Сканировать карту</string>
|
||||
<string name="home_button_yes">Да! Отсканировать</string>
|
||||
<string name="wallet_button_scan">Сканировать</string>
|
||||
<string name="wallet_button_send">Отправить</string>
|
||||
<string name="wallet_button_create_wallet">Создать кошелек</string>
|
||||
<string name="wallet_title">Tangem</string>
|
||||
<string name="wallet_choice_wallet_option_title">Выбрите опцию</string>
|
||||
<string name="wallet_balance_token_title">Токен</string>
|
||||
<string name="wallet_balance_tokens_title">Токены</string>
|
||||
<string name="wallet_balance_verified">Подтвержденный баланс</string>
|
||||
<string name="wallet_balance_loading">Загрузка баланса…</string>
|
||||
<string name="wallet_balance_blockchain_unreachable">Блокчейн недоступен</string>
|
||||
<string name="wallet_error_no_account">Аккаунт не создан</string>
|
||||
<string name="wallet_error_no_account_subtitle_format">Загрузите %1$s+ %2$s для создания учетной записи</string>
|
||||
<string name="wallet_error_empty_card">Карта пуста</string>
|
||||
<string name="wallet_error_empty_card_subtitle">Создайте кошелек, чтобы начать пользоваться картой Tangem</string>
|
||||
<string name="wallet_error_unsupported_blockchain">Эта карта не поддерживается</string>
|
||||
<string name="wallet_error_unsupported_blockchain_subtitle">Ваша карта Tangem предназначена для работы с другим приложением. Пожалуйста, ознакомьтесь с названием и инструкциями на вашей карте и установите правильное приложение.</string>
|
||||
<string name="wallet_balance_tx_in_progress">Транзакция в процессе…</string>
|
||||
<string name="wallet_pending_tx_sending_address_format">до %s</string>
|
||||
<string name="wallet_pending_tx_receiving_address_format">от %s</string>
|
||||
<string name="wallet_pending_tx_receiving">Получение\u0020</string>
|
||||
<string name="wallet_pending_tx_sending">Отправка\u0020</string>
|
||||
<string name="wallet_address_button_explore">Посмотреть адрес</string>
|
||||
<string name="wallet_address_button_create_payid">Создать PayString</string>
|
||||
<string name="wallet_qr_title_format">%s кошелек</string>
|
||||
<string name="wallet_create_payid">Создать PayString</string>
|
||||
<string name="wallet_create_payid_card_format">Карта: %s</string>
|
||||
<string name="wallet_create_payid_hint">PayString имя</string>
|
||||
<string name="wallet_create_payid_domain">$payid.tangem.com</string>
|
||||
<string name="wallet_create_payid_button_title">Создать</string>
|
||||
<string name="wallet_create_payid_info">Ваша PayString — это уникальная для вас информация, такая как номер телефона, электронная почта или ABN.</string>
|
||||
<string name="wallet_create_payid_success_message">PayString успешно создан и скопирован в буфер обмена</string>
|
||||
<string name="wallet_create_payid_error_message">Ошибка при создании PayString</string>
|
||||
<string name="wallet_create_payid_error_already_created">Такой PayString уже существует. Попробуйте другой.</string>
|
||||
<string name="send_destination_hint_address_payid">Адрес или PayString</string>
|
||||
<string name="send_destination_hint_address">Адрес</string>
|
||||
<string name="send_title">Отправить</string>
|
||||
<string name="send_network_fee_title">Комиссия сети</string>
|
||||
<string name="send_amount_label">Сумма</string>
|
||||
<string name="send_fee_label">Комиссия</string>
|
||||
<string name="send_total_label">Всего</string>
|
||||
<string name="send_max_amount_label">Максимальная сумма</string>
|
||||
<string name="send_validation_invalid_address">Неверный адрес</string>
|
||||
<string name="send_validation_invalid_amount">Недопустимая сумма</string>
|
||||
<string name="send_validation_amount_exceeds_balance">Сумма превышает баланс</string>
|
||||
<string name="send_validation_invalid_total">Общая сумма превышает баланс</string>
|
||||
<string name="send_validation_invalid_fee">Комиссия превышает баланс</string>
|
||||
<string name="send_fee_picker_low">Низкий</string>
|
||||
<string name="send_fee_picker_normal">Нормальный</string>
|
||||
<string name="send_fee_picker_priority">Приоритетный</string>
|
||||
<string name="send_fee_include_description">Включить коммисию</string>
|
||||
<string name="send_total_subtitle_format">%1$s %2$s будет отправлено</string>
|
||||
<string name="send_total_subtitle_fiat_format">≈ %1$s (включая комиссию: %2$s)</string>
|
||||
<string name="send_total_subtitle_asset_format">%1$s %2$s и %3$s %4$s будут отправлены</string>
|
||||
<string name="send_balance_subtitle_format">Баланс: %1$s %2$s</string>
|
||||
<string name="send_transaction_success">Транзакция успешно подписана и отправлена в блокчейн. Баланс кошелька будет обновлен через некоторое время</string>
|
||||
<string name="details_title">Подробности</string>
|
||||
<string name="details_row_title_cid">ID карты</string>
|
||||
<string name="details_row_title_issuer">Эмитент</string>
|
||||
<string name="details_row_title_signed_hashes">Подписано</string>
|
||||
<string name="details_row_subtitle_signed_hashes_format">%s хэшей</string>
|
||||
<string name="details_row_title_currency">Валюта приложения</string>
|
||||
<string name="details_section_title_settings">Настройки</string>
|
||||
<string name="details_section_title_card">Карта</string>
|
||||
<string name="details_row_title_validate">Подтвердить карту</string>
|
||||
<string name="details_row_title_manage_security">Управление безопасностью</string>
|
||||
<string name="details_row_title_erase_wallet">Удалить кошелек</string>
|
||||
<string name="details_erase_wallet_warning">Это действие необратимо. Если после удаления кошелька кто-то отправит на него средства, то Вы не сможете их вывести.</string>
|
||||
<string name="details_security_management_warning">Если вы забудете код, Вы потеряете возможность использовать карту. Невозможно восстановить или изменить код, если вы его потеряете.</string>
|
||||
<string name="details_manage_security_title">Управление безопасностью</string>
|
||||
<string name="details_manage_security_long_tap">Длительное удержание</string>
|
||||
<string name="details_manage_security_long_tap_description">Этот механизм защищает карту от бесконтактной атаки. Это обеспечит задержку между приемом и выполнением команды. После первой подписанной транзакции этот телефон будет привязан к карте, и транзакции будут подписаны без задержки.</string>
|
||||
<string name="details_manage_security_passcode">Пароль</string>
|
||||
<string name="details_manage_security_passcode_description">Перед выполнением любой команды, влекущей за собой изменение состояния карты, вам необходимо будет ввести пароль.</string>
|
||||
<string name="details_manage_security_access_code">Код доступа</string>
|
||||
<string name="details_manage_security_access_code_description">Перед сканированием карты вам нужно будет ввести правильный код доступа.</string>
|
||||
<string name="alert_old_device_this_card">У Вас могут возникнуть проблемы с NFC на некоторых iPhone 7/7+ во время извлечения.</string>
|
||||
<string name="alert_card_signed_transactions">Эта карта уже пополнялась и подписывала транзакции в прошлом. Рассмотрите возможность немедленного снятия всех средств, если Вы получили эту карту из ненадежного источника.</string>
|
||||
<string name="alert_title">Предупреждение</string>
|
||||
<string name="alert_unsupported_card">Эта карта не предназначена для работы с этим приложением</string>
|
||||
<string name="alert_developer_card">Карта, которую Вы отсканировали, является картой для разработчиков. Не принимайте ее в качестве оплаты.</string>
|
||||
<string name="alert_old_card">Карты Tangem, выпущенные до сентября 2019 года, в настоящее время не могут быть извлечены с помощью iPhone. Мы усердно работаем с Apple, чтобы сделать это возможным в будущих версиях iOS.</string>
|
||||
<string name="initial_message_sign_header">Нажмите, чтобы подписать</string>
|
||||
<string name="initial_message_sign_body">Приложите карту к телефону, как показано выше.</string>
|
||||
<string name="initial_message_purge_wallet_body">Приложите, чтобы удалить кошелек</string>
|
||||
<string name="initial_message_create_wallet_body">Приложите, чтобы создать кошелек</string>
|
||||
<string name="initial_message_change_access_code_body">Приложите, чтобы изменить код доступа</string>
|
||||
<string name="initial_message_change_passcode_body">Приложите, чтобы изменить пароль</string>
|
||||
<string name="payid_service_error_loading">Неверный PayString</string>
|
||||
<string name="disclaimer_title">Условия использования</string>
|
||||
<string name="send_error_fee_request_failed">Не удалось получить комиссию</string>
|
||||
<string name="send_error_no_target_account">Целевая учетная запись не создана. Сумма для отправки должна быть %1$s %2$s + плата за создание или больше</string>
|
||||
<string name="wallet_notification_no_internet">Нет соединения с интернетом</string>
|
||||
<string name="send_error_unknown">Неизвестная ошибка</string>
|
||||
<string name="send_error_payid_verification_failed">Ошибка проверки PayString</string>
|
||||
<string name="send_error_payid_unsupported_by_blockchain">PayString не поддерживается блокчейном</string>
|
||||
<string name="send_error_payid_not_registered">PayString не зарегистрирован</string>
|
||||
<string name="send_error_payid_request_failed">Не удалось выполнить запрос PayString</string>
|
||||
<string name="send_error_address_same_as_wallet">Адрес совпадает с адресом кошелька</string>
|
||||
<string name="send_error_insufficient_balance">Недостаточный баланс</string>
|
||||
<string name="send_error_blockchain_internal">Внутренняя ошибка блокчейна</string>
|
||||
<string name="send_error_invalid_fee_value">Неверная комиссия</string>
|
||||
<string name="send_error_dust_amount_format">Минимальная сумма: %s</string>
|
||||
<string name="send_error_dust_change">Сдача слишком мала</string>
|
||||
<string name="send_error_no_account_xlm">Для создания учетной записи отправьте 1+ XLM на этот адрес</string>
|
||||
<string name="wallet_notification_address_copied">Адрес скопирован в буфер обмена</string>
|
||||
<string name="wallet_create_payid_empty">Сначала введите желаемую PayString</string>
|
||||
<string name="initial_message_scan_header">Приложите, чтобы отсканировать</string>
|
||||
<string name="initial_message_tap_header">Приложите карту</string>
|
||||
<string name="details_notification_erase_wallet_not_possible">Ваш баланс на этом кошельке не равен нулю, или у Вас есть неподтвержденные транзакции</string>
|
||||
<string name="details_notification_security_option_already_active">Это текущая активная опция</string>
|
||||
<string name="xtz_withdrawal_message_warning">Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ</string>
|
||||
<string name="xtz_withdrawal_message_reduce">Уменьшить на %s XTZ</string>
|
||||
<string name="xtz_withdrawal_message_ignore">Нет, отправить все</string>
|
||||
<string name="scan_card_error">Ошибка сканирования карты. Попробуй снова</string>
|
||||
<string name="wallet_button_buy">Купить</string>
|
||||
<string name="wallet_button_sell">Продать</string>
|
||||
<string name="wallet_button_trade">Торговать</string>
|
||||
<string name="wallet_address_chip_default">По умолчанию</string>
|
||||
<string name="wallet_address_chip_compatibility">Совместимость</string>
|
||||
<string name="wallet_address_chip_legacy">Устаревший</string>
|
||||
<string name="wallet_button_create_twin_wallet">Создать кошелек</string>
|
||||
<string name="wallet_error_empty_twin_card">Создать кошелек</string>
|
||||
<string name="wallet_error_empty_twin_card_subtitle">Сгенерируйте ключи кошелька на обеих картах, чтобы начать использовать свои Twin карты.</string>
|
||||
<string name="twins_onboarding_title">Tangem Twin</string>
|
||||
<string name="twins_onboarding_subtitle">Один кошелек. Две карты.</string>
|
||||
<string name="twins_onboarding_description_format">Одна, которую Вы держите в руках, и вторая карта с номером #%s.</string>
|
||||
<string name="wallet_twins_chip_format">Карта %1d из %2d</string>
|
||||
<string name="details_row_title_twins_recreate">Пересоздать Twin кошелек</string>
|
||||
<string name="details_row_title_card_tou">Условия использования карты</string>
|
||||
<string name="twins_recreate_toolbar">Tangem Twin</string>
|
||||
<string name="twins_recreate_warning">Это действие необратимо. У Вас не будет доступа к старому кошельку.</string>
|
||||
<string name="twins_recreate_title_format">Приложите Twin карту #%s</string>
|
||||
<string name="twins_recreate_title_preparing">Подготовка карты</string>
|
||||
<string name="twins_recreate_title_creating_wallet">Создание кошелька</string>
|
||||
<string name="twins_recreate_subtitle">Процедура создания кошелька состоит из трех шагов. Вы должны пройти его до конца, иначе вам придется начинать сначала.</string>
|
||||
<string name="twins_recreate_button_format">Сканировать карту #%s</string>
|
||||
<string name="twins_recreate_alert">Вы уже начали процесс пересоздания кошелька. Если Вы прервете его, вы не сможете использовать свои карты, пока не запустите его снова и не завершите пересоздание кошелька.</string>
|
||||
<string name="twins_wrong_card_error">Вы приложили ту же карту. Чтобы создать кошелек, вам нужно приложить другу Twin карту.</string>
|
||||
<string name="notification_twins_recreate_success">Адрес кошелька успешно создан</string>
|
||||
<string name="common_start">Начать</string>
|
||||
<string name="common_back">Назад</string>
|
||||
<string name="common_add">Добавить</string>
|
||||
<string name="common_remove">Удалить</string>
|
||||
<string name="common_search">Поиск</string>
|
||||
<string name="send_extras_hint_memo">Памятка</string>
|
||||
<string name="send_extras_hint_destination_tag">Тег назначения</string>
|
||||
<string name="send_error_invalid_destination_tag">Недопустимый тег назначения. Он не будет добавлен в транзакцию</string>
|
||||
<string name="send_error_invalid_memo_id">Недопустимый идентификатор памятки. Он не будет добавлен в транзакцию</string>
|
||||
<string name="details_section_title_app">Приложение</string>
|
||||
<string name="details_row_title_send_feedback">Отправить отзыв</string>
|
||||
<string name="alert_app_feedback_sent_title">Успешно отправлено</string>
|
||||
<string name="alert_app_feedback_sent_message">Спасибо за ваш отзыв</string>
|
||||
<string name="alert_negative_app_rate_sent_title">Ваши предложения отправлены</string>
|
||||
<string name="alert_negative_app_rate_sent_message">Спасибо за ваш отзыв. Мы ответим как можно скорее</string>
|
||||
<string name="alert_failed_to_send_email_title">Не удалось отправить электронное письмо</string>
|
||||
<string name="alert_failed_to_send_email_message">Причина: %s</string>
|
||||
<string name="alert_failed_to_send_transaction_title">Не могу отправить транзакцию</string>
|
||||
<string name="alert_failed_to_send_transaction_message">Причина: %s. Хотите отправить отзыв?</string>
|
||||
<string name="alert_troubleshooting_scan_card_title">У Вас возникли трудности со сканированием вашей карты?</string>
|
||||
<string name="alert_troubleshooting_scan_card_message">Пожалуйста, попробуйте приложить карту точно так, как показано на анимации, или обратитесь в поддержку.</string>
|
||||
<string name="alert_troubleshooting_scan_card_ok">Отмена</string>
|
||||
<string name="alert_button_try_again">Попробуйте снова</string>
|
||||
<string name="alert_button_request_support">Обратиться в поддержку</string>
|
||||
<string name="alert_button_send_feedback">Отправить отзыв</string>
|
||||
<string name="warning_button_really_cool">Очень круто!</string>
|
||||
<string name="warning_button_can_be_better">Может быть лучше</string>
|
||||
<string name="warning_rate_app_title">Один вопрос</string>
|
||||
<string name="warning_rate_app_message">Вам нравится приложение Tangem?</string>
|
||||
<string name="custom_token_creation_error_empty_field">Все поля обязательны к заполнению</string>
|
||||
<string name="manage_tokens_no_tokens">Токенов пока нет</string>
|
||||
<string name="manage_tokens_section_title_added_tokens">Добавленные токены</string>
|
||||
<string name="manage_tokens_alert_remove_token_title">Удалить токен %s</string>
|
||||
<string name="manage_tokens_alert_remove_token_message">Вы уверены, что хотите удалить этот токен?</string>
|
||||
<string name="add_tokens_title">Добавить токены</string>
|
||||
<string name="add_token_button">Добавить токен</string>
|
||||
<string name="add_token_search_hint">Начните поиск</string>
|
||||
<string name="manage_tokens_title">Управление токенами</string>
|
||||
<string name="add_custom">Добавить пользовательский</string>
|
||||
<string name="add_token_section_title_custom_tokens">Пользовательские токены</string>
|
||||
<string name="add_token_section_title_popular_tokens">Популярные токены</string>
|
||||
<string name="add_custom_token_title">Добавить пользовательский токен</string>
|
||||
<string name="custom_token_creation_error_empty_fields">Пожалуйста заполните все поля</string>
|
||||
<string name="custom_token_creation_error_wrong_decimals">Введенное число не является допустимым десятичным числом</string>
|
||||
<string name="custom_token_name_input_title">Имя</string>
|
||||
<string name="custom_token_token_symbol_input_title">Символ токена</string>
|
||||
<string name="custom_token_contract_address_input_title">Адрес контракта</string>
|
||||
<string name="custom_token_decimals_input_title">Десятичные</string>
|
||||
<string name="custom_token_name_input_placeholder">бывший. USD Coin</string>
|
||||
<string name="custom_token_token_symbol_input_placeholder">бывший. USDC</string>
|
||||
<string name="add_token_added">Добавлен</string>
|
||||
<string name="remove_token">Удалить токен</string>
|
||||
<string name="token_icon">Значок токена</string>
|
||||
<string name="details_section_title_blockchain">Блокчейн</string>
|
||||
<string name="details_row_title_manage_tokens">Управление токенами</string>
|
||||
<string name="add_tokens_subtitle_blockchains">Блокчейны</string>
|
||||
<string name="add_tokens_subtitle_ethereum_tokens">Ethereum токены</string>
|
||||
<string name="add_tokens_subtitle_bsc_tokens">Binance Smart Chain токены</string>
|
||||
<string name="add_tokens_subtitle_binance_tokens">Binance Chain токены</string>
|
||||
<string name="add_tokens_subtitle_avalanche_tokens">Avalanche C-Chain токены</string>
|
||||
<string name="add_tokens_subtitle_polygon_tokens">Polygon токены</string>
|
||||
<string name="wallet_address_button_copy">Копировать</string>
|
||||
<string name="wallet_address_button_share">Поделиться</string>
|
||||
<string name="wallet_button_add_tokens">+ Добавить токены</string>
|
||||
<string name="wallet_pending_transaction_warning">Пожалуйста, дождитесь завершения транзакции, чтобы иметь возможность отправить средства</string>
|
||||
<string name="warning_failed_to_verify_card_title">Проверка подлинности не удалась</string>
|
||||
<string name="warning_failed_to_verify_card_message">Эта карта может быть производственным образцом или подделкой.</string>
|
||||
<string name="warning_important_security_info">Важная информация о безопасности \u26A0</string>
|
||||
<string name="warning_signed_tx_previously">Эта карта ранее подписывала транзакции</string>
|
||||
<string name="warning_button_learn_more">Узнать подробнее</string>
|
||||
<string name="alert_button_i_understand">Я понял</string>
|
||||
<string name="warning_low_signatures_format">На этой карте доступно только %s подписей. Вы должны вывести все свои средства.</string>
|
||||
<string name="common_disconnect">Отключить</string>
|
||||
<string name="common_sign">Подписать</string>
|
||||
<string name="common_sign_and_send">Подписать и отправить</string>
|
||||
<string name="common_reject">Отклонить</string>
|
||||
<string name="warning_testnet_card_message">Это тестовая карта. Не принимайте ее в качестве оплаты. Она должна использоваться только в целях тестирования и разработки.</string>
|
||||
<string name="wallet_dialog_choose_trade_action">Вы хотите купить или продать криптовалюту?</string>
|
||||
<string name="error_update_app">К сожалению, текущая версия приложения не готова к работе с этой картой, проверьте наличие обновлений.</string>
|
||||
<string name="home_welcome_header">Добро пожаловать в Tangem</string>
|
||||
<string name="home_welcome_body">Самый безопасный способ покупать, использовать и\n хранить криптовалюту</string>
|
||||
<string name="home_button_get_new_card">Получить новую карту</string>
|
||||
<string name="onboarding_title">Активация карты</string>
|
||||
<string name="onboarding_button_what_does_it_mean">Как это работает?</string>
|
||||
<string name="onboarding_button_receive_crypto">Получить криптовалюту</string>
|
||||
<string name="onboarding_create_wallet_header">Создать кошелек</string>
|
||||
<string name="onboarding_create_wallet_body">Давайте сгенерируем все ключи на вашей карте и создадим безопасный кошелек</string>
|
||||
<string name="onboarding_create_wallet_button_create_wallet">Создать кошелек</string>
|
||||
<string name="onboarding_top_up_header">Пополните свой кошелек</string>
|
||||
<string name="onboarding_top_up_body">Чтобы начать, просто пополните карту на любую сумму</string>
|
||||
<string name="onboarding_top_up_body_no_account_error">Чтобы начать, просто пополните кошелек более чем на %s %s.</string>
|
||||
<string name="onboarding_top_up_button_but_crypto">Купить криптовалюту</string>
|
||||
<string name="onboarding_top_up_button_show_wallet_address">Показать адрес кошелька</string>
|
||||
<string name="onboarding_dialog_wallet_address">Отсканируйте адрес, чтобы пополнить кошелек</string>
|
||||
<string name="onboarding_done_header">Успешно!</string>
|
||||
<string name="onboarding_done_body">Ваша криптокарта активирована и готова к использованию</string>
|
||||
<string name="onboarding_done_button_continue">Продолжить</string>
|
||||
<string name="onboarding_balance_title">Баланс</string>
|
||||
<string name="address_qr_code_message_format">Отправляйте только %s (%s) на этот адрес. Отправка любой другой валюты приведет к ее безвозвратной потере.</string>
|
||||
<string name="address_qr_code_message_token_format">Отправляйте только %s (%s) из сети %s на этот адрес. Отправка любой другой валюты приведет к ее безвозвратной потере.</string>
|
||||
<string name="onboarding_twins_interrupt_warning">Если процесс повторного создания кошелька каким-либо образом прервется, вам придется начать все сначала.</string>
|
||||
<string name="onboarding_twin_exit_warning">Процесс связывания карт частично завершен. Вы не можете выйти из него сейчас.</string>
|
||||
<string name="onboarding_error_create_primary_wallet">Внутренняя ошибка: не удается создать менеджер кошельков</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">Блокчейн недоступен. Попробуй позже</string>
|
||||
<string name="warning_button_ok">Хорошо, понял!</string>
|
||||
<string name="onboarding_success">Успешно!</string>
|
||||
<string name="onboarding_getting_started">Начнем</string>
|
||||
<string name="onboarding_button_backup_now">Выполнить резервное копирование</string>
|
||||
<string name="onboarding_button_get_backup_card">Получить резервную карту</string>
|
||||
<string name="onboarding_button_skip_backup">Оставить на потом</string>
|
||||
<string name="onboarding_button_finalize_backup">Завершить процесс резервного копирования</string>
|
||||
<string name="onboarding_button_add_backup_card">+ Добавить резервную карту</string>
|
||||
<string name="onboarding_button_backup_card_format">Сканировать карту #%d</string>
|
||||
<string name="onboarding_button_scan_origin_card">Сканировать основную карту</string>
|
||||
<string name="onboarding_button_add_more_cards">Добавить больше карт</string>
|
||||
<string name="onboarding_title_backup_card">Сделайте резервную копию вашего кошелька</string>
|
||||
<string name="onboarding_title_no_backup_cards">Нет резервных карт</string>
|
||||
<string name="onboarding_title_scan_origin_card">Подготовьте свою карту</string>
|
||||
<string name="onboarding_title_one_backup_card">Добавлена одна резервная карта</string>
|
||||
<string name="onboarding_title_two_backup_cards">Добавлены две резервные карты</string>
|
||||
<string name="onboarding_title_backup_card_format">Резервная карта #%d</string>
|
||||
<string name="onboarding_subtitle_backup_card">Вы можете привязать до трех карт к одному кошельку.</string>
|
||||
<string name="onboarding_subtitle_no_backup_cards">Чтобы начать процесс резервного копирования, добавьте еще максимум 2 карты</string>
|
||||
<string name="onboarding_subtitle_scan_origin_card_format">Подготовьте основную карту с номером %s</string>
|
||||
<string name="onboarding_subtitle_scan_origin_card">Подготовьте основную карту</string>
|
||||
<string name="onboarding_subtitle_one_backup_card">Вы можете добавить еще одну карту или завершить процесс резервного копирования</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards">Добавлено максимальное количество карт.</string>
|
||||
<string name="onboarding_subtitle_backup_warning">Если процесс резервного копирования будет прерван каким-либо образом, вам придется начать все сначала.</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить?</string>
|
||||
<string name="onboarding_access_code_intro_title">Создать код доступа</string>
|
||||
<string name="onboarding_access_code_repeat_code_title">Введите код доступа повторно</string>
|
||||
<string name="onboarding_access_code_feature_1_title">Защитить</string>
|
||||
<string name="onboarding_access_code_feature_2_title">Персонализировать</string>
|
||||
<string name="onboarding_access_code_feature_3_title">Восстановить</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Вам необходимо установить единый код доступа для защиты всех ваших кошельков.</string>
|
||||
<string name="onboarding_access_code_feature_2_description">Позже Вы сможете установить индивидуальный код доступа для каждой карты.</string>
|
||||
<string name="onboarding_access_code_feature_3_description">Код доступа можно восстановить с помощью привязанной карты, не храните все карты в одном месте.</string>
|
||||
<string name="onboarding_access_code_hint">Выберите любое слово, фразу или номер в качестве кода доступа.</string>
|
||||
<string name="onboarding_access_code_too_short">Код доступа должен состоять не менее чем из 4 символов.</string>
|
||||
<string name="onboarding_access_codes_doesnt_match">Введенный код доступа не соответствует исходному коду доступа</string>
|
||||
<string name="common_create">Создать</string>
|
||||
<string name="common_submit">Подтвердить</string>
|
||||
<string name="onboarding_subtitle_success_backup">Вы создали 2 резервные карты, и теперь эти карты готовы к использованию.</string>
|
||||
<string name="onboarding_navbar_title_creating_backup">Создание резервной копии</string>
|
||||
<string name="onboarding_backup_exit_warning">Процесс резервного копирования частично завершен. Вы не можете выйти из него сейчас.</string>
|
||||
<string name="onboarding_wallet_info_title_first">Резервный кошелек</string>
|
||||
<string name="onboarding_wallet_info_title_second">Идентичные карты</string>
|
||||
<string name="onboarding_wallet_info_title_third">Код доступа</string>
|
||||
<string name="onboarding_wallet_info_title_fourth">Восстановление кода доступа</string>
|
||||
<string name="onboarding_wallet_info_subtitle_first">Вы можете сделать до двух резервных копий карты Tangem Wallet.</string>
|
||||
<string name="onboarding_wallet_info_subtitle_second">Все резервные карты могут использоваться как полнофункциональные с одинаковыми ключами.</string>
|
||||
<string name="onboarding_wallet_info_subtitle_third">Вы сможете установить код доступа для защиты своих кошельков.</string>
|
||||
<string name="onboarding_wallet_info_subtitle_fourth">Код доступа можно восстановить с помощью одной из резервных карт.</string>
|
||||
<string name="onboarding_subtitle_success_tangem_wallet_onboarding">Ваша карта Tangem Wallet настроена и готова к использованию.</string>
|
||||
<string name="onboarding_subtitle_success_backup_one_card">Вы создали 1 резервную карту, и теперь эта карта готова к использованию.</string>
|
||||
<string name="common_origin_card">Основная карта</string>
|
||||
<string name="onboarding_alert_i_understand">Я понимаю</string>
|
||||
<string name="details_row_title_backup_status">Статус резервного копирования</string>
|
||||
<string name="details_backup_status_format_active">Активный. Количество резервных карт: %d</string>
|
||||
<string name="details_backup_status_format_linked">Связано. Количество резервных карт: %d</string>
|
||||
<string name="details_backup_status_no_backup">Нет резервной копии</string>
|
||||
<string name="details_row_title_create_backup">Создать резервную копию</string>
|
||||
<string name="welcome_interrupted_backup_alert_message">У Вас есть прерванное резервное копирование. Хотите возобновить?</string>
|
||||
<string name="welcome_interrupted_backup_alert_resume">Да, возобновить</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Отказаться</string>
|
||||
<string name="welcome_interrupted_backup_discard_title">Это необратимое действие</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">Если сейчас отменить резервное копирование, то придется вернуть карты до заводских настроек, чтобы начать заново</string>
|
||||
<string name="welcome_interrupted_backup_discard_resume">Возобновить резервное копирование</string>
|
||||
<string name="welcome_interrupted_backup_discard_discard">Отказаться</string>
|
||||
<string name="onboarding_title_prepare_origin">Основная карта</string>
|
||||
<string name="onboarding_button_backup_origin">Сканировать основную карту</string>
|
||||
<string name="onboarding_button_continue_wallet">Перейти к моему кошельку</string>
|
||||
<string name="card_label_number_format">Карта %1s из %2s</string>
|
||||
<string name="send_title_currency_format">Отправка %s</string>
|
||||
<string name="onboarding_subtitle_scan_backup_card_format">Подготовьте резервную карту с номером %s</string>
|
||||
<string name="onboarding_subtitle_scan_primary_card_format">Подготовьте основную карту с номером %s</string>
|
||||
<string name="details_row_title_reset_factory_settings">Сброс до заводских настроек</string>
|
||||
<string name="details_row_title_reset_factory_settings_warning">Это действие необратимо. Если после сброса карты кто-то отправит на нее средства, то Вы не сможете их вывести.</string>
|
||||
<string name="details_manage_security_access_code_disclaimer">Код доступа доступен только для карт с резервной копией.</string>
|
||||
<string name="solana_rent_warning">Сеть Solana взымает арендную плату в размере %s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %s, чтобы использовать его бесплатно.</string>
|
||||
<string name="token_symbol_address_format">%1s (%2s)</string>
|
||||
<string name="alert_signed_hashes_message">Эта карта не является векселем на предъявителя. В настоящее время мы не можем сопоставить количество подписей на карте с информацией в блокчейне. Это нормально, но в редких случаях может означать, что предыдущий владелец скрывает автономную подпись, что является проблемой безопасности.\n\nНе принимайте эту карту в качестве физического платежа от кого-то, кому Вы не доверяете.\n\nВо всех остальных отношениях - это совершенно безопасно.\n\nTangem — единственный аппаратный кошелек, предлагающий защиту от подсчета подписей.</string>
|
||||
<string name="wallet_connect">Wallet Connect</string>
|
||||
<string name="wallet_connect_create_tx_message">Запрос на создание транзакции для %2s\n%3s\n\nСумма: %4s\nКомиссия: %5s\nВсего: %6s\nБаланс: %7s</string>
|
||||
<string name="wallet_connect_request_session_start">Запрос на запуск сеанса для карты с идентификатором %1s\nдля %2s\n\nURL: %3s</string>
|
||||
<string name="wallet_connect_sessions_title">Сеансы подключения кошелька</string>
|
||||
<string name="wallet_connect_session_opened">Сеанс WalletConnect открыт с %s</string>
|
||||
<string name="wallet_connect_no_sessions_title">Упс. Нет сессий.</string>
|
||||
<string name="wallet_connect_no_sessions_message">Нет открытых сессий WalletConnect</string>
|
||||
<string name="wallet_connect_open_session">Открытая сессия</string>
|
||||
<string name="wallet_connect_card_number">Карта: %s</string>
|
||||
<string name="wallet_connect_scan_card_message">Коснитесь карты, чтобы привязать ее к кошельку.</string>
|
||||
<string name="wallet_connect_create_tx_not_enough_funds">Не удается отправить транзакцию. Недостаточно средств.</string>
|
||||
<string name="wallet_connect_alert_sign_message">Просьба подписать сообщение\nкартой %s\n\n</string>
|
||||
<string name="wallet_connect_personal_sign_message">Сообщение для %s:\n%s</string>
|
||||
<string name="wallet_connect_clipboard_alert">Буфер обмена содержит код WalletConnect. Использовать скопированное значение или отсканировать QR-код</string>
|
||||
<string name="wallet_connect_paste_from_clipboard">Вставить из буфера обмена</string>
|
||||
<string name="wallet_connect_scan_new_code">Сканировать новый код</string>
|
||||
<string name="wallet_connect_scanner_error_no_ethereum_wallet">Эту карту нельзя использовать для установки сеанса WalletConnect.</string>
|
||||
<string name="wallet_connect_could_not_complete">Операция не может быть завершена</string>
|
||||
<string name="wallet_connect_same_wcuri">Операция не может быть завершена. \n\nВы уже установили сеанс WalletConnect с этими параметрами.</string>
|
||||
<string name="wallet_connect_error_timeout">Не удалось установить сеанс WalletConnect: ошибка времени выполнения. Пожалуйста, повторите попытку позже.</string>
|
||||
<string name="wallet_connect_bnb_transaction_signed">Транзакция BNB успешно подписана и отправлена в DApp.</string>
|
||||
<string name="wallet_connect_bnb_sign_message">DApp %s, запрашивает\nподпись транзакции BNB с\nкартой: %s\n\n%s</string>
|
||||
<string name="wallet_connect_bnb_transaction_message">Сведения о транзакции:\nОт: %s\nКому: %s\nСумма: %s</string>
|
||||
<string name="wallet_connect_bnb_trade_order_message">Торговый ордер на %s\nЦена: %s\nСумма к получению: %s\nСумма к оплате: %s</string>
|
||||
<string name="feedback_subject_rate_negative">Мои предложения</string>
|
||||
<string name="feedback_subject_scan_failed">Не могу отсканировать карту</string>
|
||||
<string name="feedback_subject_tx_failed">Не могу отправить транзакцию</string>
|
||||
<string name="feedback_subject_tx_push_failed">Не могу протолкнуть транзакцию</string>
|
||||
<string name="feedback_subject_support_tangem">Обращение в поддержку Tangem</string>
|
||||
<string name="feedback_subject_support">Обращение в поддержку</string>
|
||||
<string name="feedback_preface_rate_negative">Расскажите, каких функций Вам не хватает, и мы постараемся Вам помочь.</string>
|
||||
<string name="feedback_preface_scan_failed">Скажите, пожалуйста, какая у Вас карта?</string>
|
||||
<string name="feedback_preface_tx_failed">Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая маленькая деталь может помочь.</string>
|
||||
<string name="feedback_preface_support">Привет, команда поддержки,</string>
|
||||
<string name="feedback_preface_tx_push_failed">Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая деталь может быть полезной</string>
|
||||
<string name="feedback_data_collection_message">Информация ниже не является обязательной. Вы можете стереть её, если хотите.</string>
|
||||
</resources>
|
||||
|
|
@ -29,6 +29,11 @@
|
|||
<color name="buttonGray">#F4F5F6</color>
|
||||
<color name="textGray">#DE000000</color>
|
||||
|
||||
<color name="textBlack">#060606</color>
|
||||
<color name="iconGray">#686868</color>
|
||||
<color name="backgroundGray">#F2F2F2</color>
|
||||
<color name="chipBlack">#090E13</color>
|
||||
|
||||
<color name="twins_dark">#14181D</color>
|
||||
|
||||
|
||||
|
|
|
|||
12
app/src/main/res/values/googlepay_strings.xml
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="googlepay_button_content_description">Google Pay</string>
|
||||
<string name="buy_with_googlepay_button_content_description">Buy with Google Pay</string>
|
||||
<string name="donate_with_googlepay_button_content_description">Donate With Google Pay</string>
|
||||
<string name="pay_with_googlepay_button_content_description">Pay With Google Pay</string>
|
||||
<string name="subscribe_with_googlepay_button_content_description">Subscribe With Google Pay</string>
|
||||
<string name="book_with_googlepay_button_content_description">Book With Google Pay</string>
|
||||
<string name="checkout_with_googlepay_button_content_description">Checkout With Google Pay</string>
|
||||
<string name="order_with_googlepay_button_content_description">Order With Google Pay</string>
|
||||
<string name="view_in_googlepay_button_content_description">View In Google Pay</string>
|
||||
</resources>
|
||||
|
|
@ -110,8 +110,8 @@
|
|||
<string name="alert_card_signed_transactions">This card has been already topped up and signed transactions in the past. Consider immediate withdrawal of all funds if you have received this card from an untrusted source.</string>
|
||||
<string name="alert_title">Warning</string>
|
||||
<string name="alert_unsupported_card">This card is not designed to work with this app</string>
|
||||
<string name="alert_developer_card">The card you scanned is a development card. Don’t accept it as a payment</string>
|
||||
<string name="alert_old_card">Tangem cards manufactured before September 2019 cannot currently be extracted with an iPhone. We’re working hard with Apple to make it possible in future versions of iOS.</string>
|
||||
<string name="alert_developer_card">The card you scanned is a development card. Don\'t accept it as a payment</string>
|
||||
<string name="alert_old_card">Tangem cards manufactured before September 2019 cannot currently be extracted with an iPhone. We\'re working hard with Apple to make it possible in future versions of iOS.</string>
|
||||
|
||||
<string name="initial_message_sign_header">Tap to sign</string>
|
||||
<string name="initial_message_sign_body">Tap the card to your phone as shown above</string>
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
|
||||
<string name="payid_service_error_loading">Invalid PayString</string>
|
||||
|
||||
<string name="disclaimer_text">Legal Disclaimer
|
||||
<string name="disclaimer_text" translatable="false">Legal Disclaimer
|
||||
\n
|
||||
\n1. Tangem application (Software)
|
||||
\n
|
||||
|
|
@ -144,7 +144,7 @@
|
|||
\n
|
||||
\nc) Technical failures in the hardware of the user, including Cards, of any cryptocurrency-related software or service, e.g., data loss due to a faulty or damaged storage device.
|
||||
\n
|
||||
\nd) Security problems experienced by the user of any cryptocurrency-related software or service, e.g., unauthorized access to users’ wallets and/or accounts.
|
||||
\nd) Security problems experienced by the user of any cryptocurrency-related software or service, e.g., unauthorized access to users\' wallets and/or accounts.
|
||||
\n
|
||||
\ne) Actions or inactions of third parties and/or events experienced by third parties, e.g., bankruptcy of service providers, information security attacks on service providers, and fraud conducted by third parties.
|
||||
\n
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
<string name="alert_negative_app_rate_sent_message" translatable="false">Thank your for your feedback. We will response as soon as possible</string>
|
||||
<string name="alert_failed_to_send_email_title" translatable="false">Failed to send email</string>
|
||||
<string name="alert_failed_to_send_email_message" translatable="false">Reason: %s</string>
|
||||
<string name="alert_failed_to_send_transaction_title" translatable="false">Can’t send a transaction</string>
|
||||
<string name="alert_failed_to_send_transaction_title" translatable="false">Can\'t send a transaction</string>
|
||||
<string name="alert_failed_to_send_transaction_message" translatable="false">Reason: %s. Do you want to send feedback?</string>
|
||||
<string name="alert_troubleshooting_scan_card_title" translatable="false">Are you having difficulty scanning your card?</string>
|
||||
<string name="alert_troubleshooting_scan_card_message" translatable="false">Please try to tap the card exactly as shown in the animation or request support.</string>
|
||||
|
|
@ -115,9 +115,9 @@
|
|||
<string name="warning_important_security_info" translatable="false">Important security information \u26A0</string>
|
||||
<string name="warning_signed_tx_previously" translatable="false">This card has signed transactions in the past</string>
|
||||
<string name="warning_button_learn_more" translatable="false">Learn more</string>
|
||||
<string name="alert_signed_hashes_message" translatable="false">This card is not a bearer note. We can’t currently match the signature count on the card with the information on the blockchain. This is normal but in rare cases can mean a previous holder is holding back an offline signature, which is a security concern.
|
||||
\n\nDo not accept this card as physical payment from someone you don’t trust.
|
||||
\n\nIt’s perfectly safe in all other respects.
|
||||
<string name="alert_signed_hashes_message" translatable="false">This card is not a bearer note. We can\'t currently match the signature count on the card with the information on the blockchain. This is normal but in rare cases can mean a previous holder is holding back an offline signature, which is a security concern.
|
||||
\n\nDo not accept this card as physical payment from someone you don\'t trust.
|
||||
\n\nIt\'s perfectly safe in all other respects.
|
||||
\n\nTangem is the only hardware wallet to offer signature count protection.</string>
|
||||
<string name="alert_button_i_understand" translatable="false">I understand</string>
|
||||
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
<string name="wallet_connect_clipboard_alert" translatable="false">Clipboard contain WalletConnect code. Use copied value or scan QR-code</string>
|
||||
<string name="wallet_connect_paste_from_clipboard" translatable="false">Paste from clipboard</string>
|
||||
<string name="wallet_connect_scan_new_code" translatable="false">Scan new code</string>
|
||||
<string name="wallet_connect_scanner_error_no_ethereum_wallet" translatable="false">This card can’t be used to establish WalletConnect session</string>
|
||||
<string name="wallet_connect_scanner_error_no_ethereum_wallet" translatable="false">This card can\'t be used to establish WalletConnect session</string>
|
||||
<string name="wallet_connect_could_not_complete" translatable="false">The operation couldn\'t be completed</string>
|
||||
<string name="wallet_connect_same_wcuri" translatable="false">The operation couldn\'t be completed. \n\nYou have already established a WalletConnect session with this parameters.</string>
|
||||
<string name="wallet_connect_error_timeout" translatable="false">Failed to establish WalletConnect session: timeout error. Please, try again later.</string>
|
||||
|
|
@ -184,14 +184,14 @@
|
|||
<string name="onboarding_button_receive_crypto" translatable="false">Receive crypto</string>
|
||||
|
||||
<string name="onboarding_create_wallet_header" translatable="false">Create a wallet</string>
|
||||
<string name="onboarding_create_wallet_body" translatable="false">Let’s generate all the keys on your card and create a secure wallet</string>
|
||||
<string name="onboarding_create_wallet_body" translatable="false">Let\'s generate all the keys on your card and create a secure wallet</string>
|
||||
<string name="onboarding_create_wallet_button_create_wallet" translatable="false">Create wallet</string>
|
||||
|
||||
<string name="onboarding_top_up_header" translatable="false">Top up your wallet</string>
|
||||
<string name="onboarding_top_up_body" translatable="false">To get started, simply top up the card with any amount</string>
|
||||
<string name="onboarding_top_up_body_no_account_error" translatable="false">To get started, simply top up the wallet with more than %s %s.</string>
|
||||
<string name="onboarding_top_up_button_but_crypto" translatable="false">Buy crypto</string>
|
||||
<string name="onboarding_top_up_button_show_wallet_address" translatable="false">Show the wallet’s address</string>
|
||||
<string name="onboarding_top_up_button_show_wallet_address" translatable="false">Show the wallet\'s address</string>
|
||||
<string name="onboarding_dialog_wallet_address" translatable="false">Scan the address to top up your wallet</string>
|
||||
|
||||
<string name="onboarding_done_header" translatable="false">Success!</string>
|
||||
|
|
@ -201,8 +201,8 @@
|
|||
<string name="address_qr_code_message_format" translatable="false">Send only %s (%s) to this address. Sending any other currency will result in its irreversible loss.</string>
|
||||
<string name="address_qr_code_message_token_format" translatable="false">Send only %s (%s) from %s network to this address. Sending any other currency will result in its irreversible loss.</string>
|
||||
|
||||
<string name="onboarding_twins_interrupt_warning" translatable="false">If the process of re-creating the wallet gets interrupted in any way, you’ll have to start over.</string>
|
||||
<string name="onboarding_twin_exit_warning" translatable="false">The twinning process is partly complete. You can’t exit it now.</string>
|
||||
<string name="onboarding_twins_interrupt_warning" translatable="false">If the process of re-creating the wallet gets interrupted in any way, you\'ll have to start over.</string>
|
||||
<string name="onboarding_twin_exit_warning" translatable="false">The twinning process is partly complete. You can\'t exit it now.</string>
|
||||
|
||||
<string name="onboarding_error_create_primary_wallet" translatable="false">Internal error: can\'t create wallet manager</string>
|
||||
|
||||
|
|
@ -235,9 +235,9 @@
|
|||
<string name="onboarding_subtitle_scan_origin_card" translatable="false">Prepare the primary card</string>
|
||||
<string name="onboarding_subtitle_one_backup_card" translatable="false">You can add one more card or finalize the backup process</string>
|
||||
<string name="onboarding_subtitle_two_backup_cards" translatable="false">Max number of cards added. Finalize the backup process</string>
|
||||
<string name="onboarding_subtitle_backup_warning" translatable="false">If the process of backup gets interrupted in any way you’ll have to start over</string>
|
||||
<string name="onboarding_subtitle_backup_warning" translatable="false">If the process of backup gets interrupted in any way you\'ll have to start over</string>
|
||||
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added" translatable="false">You’ve added one backup card. When backup process is finished you can’t add more backup cards. If you have one more card, add it in backup, otherwise you can buy it in shop. Do you like to continue backup process?</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added" translatable="false">You\'ve added one backup card. When backup process is finished you can\'t add more backup cards. If you have one more card, add it in backup, otherwise you can buy it in shop. Do you like to continue backup process?</string>
|
||||
|
||||
<string name="onboarding_access_code_intro_title" translatable="false">Create Access Code</string>
|
||||
<string name="onboarding_access_code_repeat_code_title" translatable="false">Re-enter your Access Code</string>
|
||||
|
|
@ -246,7 +246,7 @@
|
|||
<string name="onboarding_access_code_feature_3_title" translatable="false">Restore</string>
|
||||
<string name="onboarding_access_code_feature_1_description" translatable="false">You have to setup a single access code to protect all yor wallets.</string>
|
||||
<string name="onboarding_access_code_feature_2_description" translatable="false">You can set an individual access code on each card later.</string>
|
||||
<string name="onboarding_access_code_feature_3_description" translatable="false">The access code can be restored with a linked card, don’t keep all cards at one place.</string>
|
||||
<string name="onboarding_access_code_feature_3_description" translatable="false">The access code can be restored with a linked card, don\'t keep all cards at one place.</string>
|
||||
<string name="onboarding_access_code_hint" translatable="false">Choose any word, phrase, or number you want as your access code.</string>
|
||||
<string name="onboarding_access_code_too_short" translatable="false">Access code must be at least 4 characters long</string>
|
||||
<string name="onboarding_access_codes_doesnt_match" translatable="false">Entered access code didn\'t match initial access code</string>
|
||||
|
|
@ -255,7 +255,7 @@
|
|||
<string name="common_submit" translatable="false">Submit</string>
|
||||
<string name="onboarding_subtitle_success_backup" translatable="false">You have created 2 backup cards, and now these cards are ready for use.</string>
|
||||
<string name="onboarding_navbar_title_creating_backup" translatable="false">Creating a backup</string>
|
||||
<string name="onboarding_backup_exit_warning" translatable="false">The backup process is partly complete. You can’t exit it now.</string>
|
||||
<string name="onboarding_backup_exit_warning" translatable="false">The backup process is partly complete. You can\'t exit it now.</string>
|
||||
|
||||
<string name="onboarding_wallet_info_title_first" translatable="false">Backup wallet</string>
|
||||
<string name="onboarding_wallet_info_title_second" translatable="false">Identical cards</string>
|
||||
|
|
@ -313,8 +313,34 @@ Price: %s\n
|
|||
Amount to receive: %s\n
|
||||
Amount to pay: %s</string>
|
||||
|
||||
<string name="solana_rent_warning" translatable="false">Solana network charges a rent of %s every 2 days. Accounts that can’t afford the rent are purged from the network. Deposit your account with more than %s to use it for free.</string>
|
||||
<string name="solana_rent_warning" translatable="false">Solana network charges a rent of %s every 2 days. Accounts that can\'t afford the rent are purged from the network. Deposit your account with more than %s to use it for free.</string>
|
||||
|
||||
<string name="token_symbol_address_format" translatable="false">%1s (%2s)</string>
|
||||
<string name="add_token_search_hint" translatable="false">Type here to search</string>
|
||||
|
||||
<string name="feedback_subject_rate_negative" translatable="false">My suggestions</string>
|
||||
<string name="feedback_subject_scan_failed" translatable="false">Can\'t scan a card</string>
|
||||
<string name="feedback_subject_tx_failed" translatable="false">Can\'t send a transaction</string>
|
||||
<string name="feedback_subject_tx_push_failed" translatable="false">Can\'t push a transaction</string>
|
||||
<string name="feedback_subject_support_tangem" translatable="false">Tangem feedback</string>
|
||||
<string name="feedback_subject_support" translatable="false">Feedback</string>
|
||||
<string name="feedback_preface_rate_negative" translatable="false">Tell us what functions you are missing, and we will try to help you.</string>
|
||||
<string name="feedback_preface_scan_failed" translatable="false">Please tell us what card do you have?</string>
|
||||
<string name="feedback_preface_tx_failed" translatable="false">Please tell us more about your issue. Every small detail can help.</string>
|
||||
<string name="feedback_preface_support" translatable="false">Hi support team,</string>
|
||||
<string name="feedback_preface_tx_push_failed" translatable="false">Please tell us more about your issue. Every small detail can help.</string>
|
||||
<string name="feedback_data_collection_message" translatable="false">Following information is optional. You can erase it if you don’t want to share it.</string>
|
||||
|
||||
<string name="shop_one_wallet" translatable="false">One Wallet</string>
|
||||
<string name="shop_3_cards" translatable="false">3 cards</string>
|
||||
<string name="shop_2_cards" translatable="false">2 cards</string>
|
||||
<string name="shop_shipping" translatable="false">Shipping</string>
|
||||
<string name="shop_free" translatable="false">Free</string>
|
||||
<string name="shop_i_have_a_promo_code" translatable="false">I have a promo code...</string>
|
||||
<string name="shop_total" translatable="false">Total</string>
|
||||
<string name="shop_other_payment_methods" translatable="false">Other payment methods</string>
|
||||
<string name="shop_buy_now" translatable="false">Buy now</string>
|
||||
<string name="shop_title" translatable="false">Order card</string>
|
||||
<string name="shop_free_delivery" translatable="false">Delivery (Free shipping)</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -147,6 +147,15 @@
|
|||
<item name="android:windowSoftInputMode">adjustResize</item>
|
||||
</style>
|
||||
|
||||
<style name="ShopChips" parent="@style/Widget.MaterialComponents.Chip.Choice">
|
||||
<item name="chipBackgroundColor">@color/selector_chip_shop</item>
|
||||
<item name="android:minWidth">100dp</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textColor">@color/selector_chip_shop_text</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
<!-- android:fontFamily="sans-serif" // roboto regular -->
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ buildscript {
|
|||
classpath "com.android.tools.build:gradle:${versions.build_gradle}"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
|
||||
classpath "com.github.dcendents:android-maven-gradle-plugin:2.1"
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
|
||||
}
|
||||
}
|
||||
|
|
|
|||