Updated on 2026-08-14

This commit is contained in:
Tangem 2020-10-13 14:39:32 +03:00
commit 5395eeda0d
54 changed files with 591 additions and 262 deletions

View file

@ -67,9 +67,9 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation 'com.tangem:blockchain:1.74.0'
implementation 'com.tangem:core:1.63.0'
implementation 'com.tangem:sdk:1.63.0'
implementation 'com.tangem:blockchain:1.81.0'
implementation 'com.tangem:core:1.67.0'
implementation 'com.tangem:sdk:1.67.0'
//lifecycle
implementation "androidx.lifecycle:lifecycle-runtime:2.2.0"

View file

@ -7,6 +7,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.features.details.ui.DetailsConfirmFragment
import com.tangem.tap.features.details.ui.DetailsFragment
import com.tangem.tap.features.details.ui.DetailsSecurityFragment
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
import com.tangem.tap.features.home.HomeFragment
import com.tangem.tap.features.send.ui.SendFragment
import com.tangem.tap.features.wallet.ui.WalletFragment
@ -42,5 +43,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.Details -> DetailsFragment()
AppScreen.DetailsConfirm -> DetailsConfirmFragment()
AppScreen.DetailsSecurity -> DetailsSecurityFragment()
AppScreen.Disclaimer -> DisclaimerFragment()
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.tap.common.redux
import com.tangem.tap.common.redux.global.globalReducer
import com.tangem.tap.common.redux.navigation.NavigationReducer
import com.tangem.tap.features.details.redux.DetailsReducer
import com.tangem.tap.features.disclaimer.redux.DisclaimerReducer
import com.tangem.tap.features.home.redux.HomeReducer
import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
import com.tangem.tap.features.wallet.redux.WalletReducer
@ -18,7 +19,8 @@ fun appReducer(action: Action, state: AppState?): AppState {
homeState = HomeReducer.reduce(action, state),
walletState = WalletReducer.reduce(action, state),
sendState = SendScreenReducer.reduce(action, state.sendState),
detailsState = DetailsReducer.reduce(action, state)
detailsState = DetailsReducer.reduce(action, state),
disclaimerState = DisclaimerReducer.reduce(action, state)
)
}

View file

@ -6,6 +6,8 @@ import com.tangem.tap.common.redux.navigation.NavigationState
import com.tangem.tap.common.redux.navigation.navigationMiddleware
import com.tangem.tap.features.details.redux.DetailsMiddleware
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.disclaimer.redux.DisclaimerMiddleware
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.home.redux.homeMiddleware
import com.tangem.tap.features.send.redux.middlewares.sendMiddleware
@ -21,7 +23,8 @@ data class AppState(
val homeState: HomeState = HomeState(),
val walletState: WalletState = WalletState(),
val sendState: SendState = SendState(),
val detailsState: DetailsState = DetailsState()
val detailsState: DetailsState = DetailsState(),
val disclaimerState: DisclaimerState = DisclaimerState()
) : StateType {
companion object {
@ -29,7 +32,8 @@ data class AppState(
return listOf(
logMiddleware, navigationMiddleware, notificationsMiddleware, globalMiddleware,
homeMiddleware, walletMiddleware, sendMiddleware,
DetailsMiddleware().detailsMiddleware
DetailsMiddleware().detailsMiddleware,
DisclaimerMiddleware().disclaimerMiddleware
)
}
}

View file

@ -14,5 +14,5 @@ sealed class GlobalAction : Action {
object RestoreAppCurrency : GlobalAction() {
data class Success(val appCurrency: FiatCurrencyName) : GlobalAction()
}
data class UpdateWalletSignedHashes(val walletSignedHashes: Int) : GlobalAction()
data class UpdateWalletSignedHashes(val walletSignedHashes: Int?) : GlobalAction()
}

View file

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

View file

@ -10,9 +10,9 @@ import java.util.regex.Pattern
class DecimalDigitsInputFilter(
digitsBeforeDecimal: Int,
digitsAfterDecimal: Int,
decimalSeparator: String
private val decimalSeparator: String
) : InputFilter {
private val pattern: Pattern = Pattern.compile("(([1-9]{1}[0-9]{0,${digitsBeforeDecimal -1}})?||[0]{1})((\\$decimalSeparator[0-9]{0,$digitsAfterDecimal})?)||(\\$decimalSeparator)?")
private val pattern: Pattern = Pattern.compile("(([1-9]{1}[0-9]{0,${digitsBeforeDecimal - 1}})?||[0]{1})((\\$decimalSeparator[0-9]{0,$digitsAfterDecimal})?)||(\\$decimalSeparator)?")
override fun filter(source: CharSequence, sourceStart: Int, sourceEnd: Int, destination: Spanned, destinationStart: Int, destinationEnd: Int): CharSequence? {
val destString = destination.toString()
@ -24,7 +24,27 @@ class DecimalDigitsInputFilter(
val resultSuffix = newDestination.substring(destinationStart, newDestination.length)
val result = resultPrefix + source.toString() + resultSuffix
val hasMatches = pattern.matcher(result).matches()
return if (hasMatches) null else ""
return if (pattern.matcher(result).matches()) {
null
} else {
val replacedWithAppropriateDecimalSeparator = setDecimalSeparator(result, decimalSeparator)
if (pattern.matcher(replacedWithAppropriateDecimalSeparator).matches()) {
decimalSeparator
} else {
""
}
}
}
}
companion object {
fun setDecimalSeparator(value: String, decimalSeparator: String): String {
if (value.contains(decimalSeparator)) return value
return if (decimalSeparator == ".") {
value.replace(",", decimalSeparator)
} else {
value.replace(".", decimalSeparator)
}
}
}
}

View file

@ -24,17 +24,17 @@ class TangemSdkManager(val activity: ComponentActivity) {
suspend fun scanNote(): CompletionResult<ScanNoteResponse> {
return runTaskAsyncReturnOnMain(ScanNoteTask(),
initialMessage = Message(activity.getString(R.string.tap_to_scan)))
initialMessage = Message(activity.getString(R.string.initial_message_scan_header)))
}
suspend fun createWallet(cardId: String?): CompletionResult<ScanNoteResponse> {
return runTaskAsyncReturnOnMain(CreateWalletAndRescanTask(), cardId,
initialMessage = Message(activity.getString(R.string.tap_to_create_wallet)))
initialMessage = Message(activity.getString(R.string.initial_message_create_wallet_body)))
}
suspend fun eraseWallet(cardId: String?): CompletionResult<PurgeWalletResponse> {
return runTaskAsyncReturnOnMain(PurgeWalletCommand(), cardId,
initialMessage = Message(activity.getString(R.string.tap_to_purge_wallet)))
initialMessage = Message(activity.getString(R.string.initial_message_purge_wallet_body)))
}
suspend fun setPasscode(cardId: String?): CompletionResult<SetPinResponse> {
@ -42,7 +42,7 @@ class TangemSdkManager(val activity: ComponentActivity) {
pinType = PinType.Pin2,
newPin1 = tangemSdk.config.defaultPin1.calculateSha256(),
newPin2 = null
), cardId, initialMessage = Message(activity.getString(R.string.tap_to_change_passcode)))
), cardId, initialMessage = Message(activity.getString(R.string.initial_message_change_passcode_body)))
}
suspend fun setAccessCode(cardId: String?): CompletionResult<SetPinResponse> {
@ -50,7 +50,7 @@ class TangemSdkManager(val activity: ComponentActivity) {
pinType = PinType.Pin1,
newPin1 = null,
newPin2 = tangemSdk.config.defaultPin2.calculateSha256()
), cardId, initialMessage = Message(activity.getString(R.string.tap_to_change_access_code)))
), cardId, initialMessage = Message(activity.getString(R.string.initial_message_change_access_code_body)))
}
suspend fun setLongTap(cardId: String?): CompletionResult<SetPinResponse> {
@ -58,7 +58,7 @@ class TangemSdkManager(val activity: ComponentActivity) {
pinType = PinType.Pin1,
newPin1 = tangemSdk.config.defaultPin1.calculateSha256(),
newPin2 = tangemSdk.config.defaultPin2.calculateSha256()
), cardId, initialMessage = Message(activity.getString(R.string.tap_the_card)))
), cardId, initialMessage = Message(activity.getString(R.string.initial_message_tap_header)))
}
private suspend fun <T : CommandResponse> runTaskAsync(

View file

@ -20,22 +20,22 @@ sealed class TapError(
override val args: List<Any>? = null
) : Throwable(), TapErrors, ArgError {
object UnknownError : TapError(R.string.error_unknown)
object PayIdAlreadyCreated : TapError(R.string.error_payid_already_created)
object PayIdCreatingError : TapError(R.string.error_creating_payid)
object UnknownError : TapError(R.string.send_error_unknown)
object PayIdAlreadyCreated : TapError(R.string.wallet_create_payid_error_already_created)
object PayIdCreatingError : TapError(R.string.wallet_create_payid_error_message)
object PayIdEmptyField : TapError(R.string.wallet_create_payid_empty)
object UnknownBlockchain : TapError(R.string.wallet_unknown_blockchain)
object NoInternetConnection : TapError(R.string.notification_no_internet)
object InsufficientBalance : TapError(R.string.error_insufficient_balance)
object BlockchainInternalError : TapError(R.string.error_blockchain_internal)
object AmountExceedsBalance : TapError(R.string.amount_exceeds_balance)
object FeeExceedsBalance : TapError(R.string.fee_exceeds_balance)
object TotalExceedsBalance : TapError(R.string.total_exceeds_balance)
object InvalidAmountValue : TapError(R.string.invalid_amount_value)
object InvalidFeeValue : TapError(R.string.invalid_fee_value)
data class DustAmount(override val args: List<Any>) : TapError(R.string.dust_amount)
object DustChange : TapError(R.string.dust_change)
data class CreateAccountUnderfunded(override val args: List<Any>) : TapError(R.string.create_account_underfunded)
object UnknownBlockchain : TapError(R.string.wallet_error_unsupported_blockchain_subtitle)
object NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
object InsufficientBalance : TapError(R.string.send_error_insufficient_balance)
object BlockchainInternalError : TapError(R.string.send_error_blockchain_internal)
object AmountExceedsBalance : TapError(R.string.send_error_amount_exceeds_balance)
object FeeExceedsBalance : TapError(R.string.send_error_fee_exceeds_balance)
object TotalExceedsBalance : TapError(R.string.send_error_total_exceeds_balance)
object InvalidAmountValue : TapError(R.string.send_error_invalid_amount)
object InvalidFeeValue : TapError(R.string.send_error_invalid_fee_value)
data class DustAmount(override val args: List<Any>) : TapError(R.string.send_error_dust_amount_format)
object DustChange : TapError(R.string.send_error_dust_change)
data class CreateAccountUnderfunded(override val args: List<Any>) : TapError(R.string.send_error_no_target_accout)
data class ValidateTransactionErrors(
override val errorList: List<TapError>,
@ -47,7 +47,7 @@ sealed class TapSdkError(override val messageResId: Int?) : Throwable(), TangemE
final override val code: Int = 1
override var customMessage: String = code.toString()
object CardForDifferentApp : TapSdkError(R.string.error_card_for_different_app)
object CardForDifferentApp : TapSdkError(R.string.alert_unsupported_card)
}

View file

@ -17,6 +17,8 @@ sealed class DetailsAction : Action {
val fiatCurrencies: List<FiatCurrencyName>? = null,
): DetailsAction()
object ShowDisclaimer : DetailsAction()
sealed class EraseWallet : DetailsAction() {
object Check : EraseWallet()

View file

@ -6,6 +6,7 @@ import com.tangem.tap.common.redux.AppState
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.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
import com.tangem.tap.preferencesStorage
@ -29,6 +30,10 @@ class DetailsMiddleware {
is DetailsAction.EraseWallet -> eraseWalletMiddleware.handle(action)
is DetailsAction.AppCurrencyAction -> appCurrencyMiddleware.handle(action)
is DetailsAction.ManageSecurity -> manageSecurityMiddleware.handle(action)
is DetailsAction.ShowDisclaimer -> {
store.dispatch(DisclaimerAction.ShowAcceptedDisclaimer)
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
}
next(action)
}

View file

@ -30,6 +30,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
is DetailsAction.ManageSecurity -> {
handleSecurityAction(action, detailsState)
}
else -> detailsState
}
}

View file

@ -20,11 +20,11 @@ class CurrencySelectionDialog {
var currentSelection = currencies.indexOfFirst { it.symbol == currentAppCurrency }
dialog = AlertDialog.Builder(context)
.setTitle(context.getString(R.string.details_currency))
.setNegativeButton(context.getString(R.string.generic_cancel)) { _, _ ->
.setTitle(context.getString(R.string.details_row_title_currency))
.setNegativeButton(context.getString(R.string.common_cancel)) { _, _ ->
store.dispatch(DetailsAction.AppCurrencyAction.Cancel)
}
.setPositiveButton(context.getString(R.string.generic_done)) { _, _ ->
.setPositiveButton(context.getString(R.string.common_done)) { _, _ ->
val selectedCurrency = currencies[currentSelection]
store.dispatch(DetailsAction.AppCurrencyAction.SelectAppCurrency(selectedCurrency.symbol))
}

View file

@ -58,9 +58,9 @@ class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
when (state.confirmScreenState) {
ConfirmScreenState.EraseWallet -> {
toolbar.title = getString(R.string.details_erase_wallet)
toolbar.title = getString(R.string.details_row_title_erase_wallet)
tv_warning_description.text = getString(R.string.details_erase_wallet_warning)
btn_confirm.text = getString(R.string.details_erase_wallet)
btn_confirm.text = getString(R.string.details_row_title_erase_wallet)
btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
null, null, getDrawable(R.drawable.ic_send), null
)
@ -68,9 +68,9 @@ class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
}
ConfirmScreenState.LongTap, ConfirmScreenState.AccessCode,
ConfirmScreenState.PassCode -> {
toolbar.title = getString(R.string.details_manage_security)
tv_warning_description.text = getString(R.string.details_manage_security_warning)
btn_confirm.text = getString(R.string.details_save_changes)
toolbar.title = getString(R.string.details_row_title_manage_security)
tv_warning_description.text = getString(R.string.details_security_management_warning)
btn_confirm.text = getString(R.string.common_save_changes)
btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
null, null, getDrawable(R.drawable.ic_save), null
)

View file

@ -64,6 +64,8 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
tv_signed_hashes.text = state.cardInfo.signedHashes.toString()
}
tv_disclaimer.setOnClickListener { store.dispatch(DetailsAction.ShowDisclaimer) }
tv_erase_wallet.setOnClickListener {
store.dispatch(DetailsAction.EraseWallet.Check)
store.dispatch(DetailsAction.EraseWallet.Proceed)

View file

@ -0,0 +1,8 @@
package com.tangem.tap.features.disclaimer.redux
import org.rekotlin.Action
sealed class DisclaimerAction: Action {
object AcceptDisclaimer : DisclaimerAction()
object ShowAcceptedDisclaimer : DisclaimerAction()
}

View file

@ -0,0 +1,24 @@
package com.tangem.tap.features.disclaimer.redux
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.preferencesStorage
import com.tangem.tap.store
import org.rekotlin.Middleware
class DisclaimerMiddleware {
val disclaimerMiddleware: Middleware<AppState> = { dispatch, state ->
{ next ->
{ action ->
when (action) {
is DisclaimerAction.AcceptDisclaimer -> {
preferencesStorage.saveDisclaimerAccepted()
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
}
}
next(action)
}
}
}
}

View file

@ -0,0 +1,21 @@
package com.tangem.tap.features.disclaimer.redux
import com.tangem.tap.common.redux.AppState
import org.rekotlin.Action
class DisclaimerReducer {
companion object {
fun reduce(action: Action, state: AppState): DisclaimerState = internalReduce(action, state)
}
}
private fun internalReduce(action: Action, state: AppState): DisclaimerState {
if (action !is DisclaimerAction) return state.disclaimerState
val disclaimerState = state.disclaimerState
return when (action) {
is DisclaimerAction.AcceptDisclaimer, DisclaimerAction.ShowAcceptedDisclaimer -> {
disclaimerState.copy(accepted = true)
}
}
}

View file

@ -0,0 +1,7 @@
package com.tangem.tap.features.disclaimer.redux
import org.rekotlin.StateType
data class DisclaimerState(
val accepted: Boolean = false
) : StateType

View file

@ -0,0 +1,63 @@
package com.tangem.tap.features.disclaimer.ui
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.tangem.tap.common.extensions.hide
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
import com.tangem.tap.store
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fragment_disclaimer.*
import org.rekotlin.StoreSubscriber
class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer),
StoreSubscriber<DisclaimerState> {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())
}
})
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
exitTransition = inflater.inflateTransition(R.transition.fade)
}
override fun onStart() {
super.onStart()
store.subscribe(this) { state ->
state.skipRepeats { oldState, newState ->
oldState.disclaimerState == newState.disclaimerState
}.select { it.disclaimerState }
}
}
override fun onStop() {
super.onStop()
store.unsubscribe(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
}
setOnClickListeners()
}
private fun setOnClickListeners() {
btn_accept.setOnClickListener { store.dispatch(DisclaimerAction.AcceptDisclaimer) }
}
override fun newState(state: DisclaimerState) {
if (activity == null) return
if (state.accepted) btn_accept.hide()
}
}

View file

@ -31,7 +31,7 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
override fun newState(state: HomeState) {
if (activity == null) return
if (state.firstLaunch) {
tv_home_description.text = getText(R.string.home_do_you_have_card)
tv_home_description.text = getText(R.string.home_welcome)
btn_shop.text = getText(R.string.home_button_no_card)
btn_yes.text = getText(R.string.home_button_yes)
} else {
@ -54,6 +54,4 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
val inflater = TransitionInflater.from(requireContext())
exitTransition = inflater.inflateTransition(R.transition.fade)
}
}

View file

@ -34,7 +34,7 @@ val homeMiddleware: Middleware<AppState> = { dispatch, state ->
is CompletionResult.Success -> {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.state.globalState.tapWalletManager.onCardScanned(result.data)
navigateToWallet()
showDisclaimerOrNavigateToWallet()
}
}
}
@ -51,6 +51,15 @@ val homeMiddleware: Middleware<AppState> = { dispatch, state ->
}
}
private fun showDisclaimerOrNavigateToWallet() {
if (preferencesStorage.wasDisclaimerAccepted()) {
navigateToWallet()
} else {
store.dispatch(NavigationAction.NavigateTo(AppScreen.Disclaimer))
}
}
private fun navigateToWallet() {
if (store.state.navigationState.backStack.isNotEmpty()) {
val currentScreen = store.state.navigationState.backStack.last()

View file

@ -55,7 +55,7 @@ abstract class BaseStoreFragment(layoutId: Int) : Fragment(layoutId) {
fun showRetrySnackbar(message: String, action: () -> Unit) {
val snackbar = Snackbar.make(mainView, message, Snackbar.LENGTH_INDEFINITE)
snackbar.setAction(getString(R.string.generic_retry)) {
snackbar.setAction(getString(R.string.common_retry)) {
snackbar.dismiss()
action()
}.show()

View file

@ -110,7 +110,7 @@ sealed class SendAction : SendScreenAction {
data class ChangeSendButtonState(val state: SendButtonState) : SendAction()
object SendSuccess : SendAction(), ToastNotificationAction {
override val messageResource: Int = R.string.send_transaction_complete
override val messageResource: Int = R.string.send_transaction_success
}
data class SendError(override val error: TapError) : SendAction(), ErrorAction

View file

@ -6,6 +6,7 @@ import com.tangem.blockchain.common.WalletManager
import com.tangem.common.extensions.isZero
import com.tangem.tap.common.CurrencyConverter
import com.tangem.tap.common.entities.TapCurrency
import com.tangem.tap.common.text.DecimalDigitsInputFilter
import com.tangem.tap.domain.TapError
import com.tangem.tap.store
import org.rekotlin.StateType
@ -143,13 +144,7 @@ data class AmountState(
}
fun restoreDecimalSeparator(value: String): String {
if (value.contains(decimalSeparator)) return value
return if (decimalSeparator == ".") {
value.replace(",", decimalSeparator)
} else {
value.replace(".", decimalSeparator)
}
return DecimalDigitsInputFilter.setDecimalSeparator(value, decimalSeparator)
}
}

View file

@ -67,7 +67,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
btnSend.setOnClickListener {
store.dispatch(SendActionUi.SendAmountToRecipient(
Message(getString(R.string.tap_to_sign))
Message(getString(R.string.initial_message_sign_header))
))
}
}
@ -144,7 +144,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
}
}
etAmountToSend.keyListener = DigitsKeyListener.getInstance("0123456789$decimalSeparator")
etAmountToSend.keyListener = DigitsKeyListener.getInstance("0123456789,.")
etAmountToSend.setOnFocusChangeListener { v, hasFocus ->
snackbarControlledByChangingFocus = true
if (hasFocus) {

View file

@ -73,11 +73,11 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
private fun handleAddressPayIdState(fg: BaseStoreFragment, state: AddressPayIdState) {
fun parseError(context: Context, error: Error?): String? {
val resId = when (error) {
Error.PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.error_payid_unsupported_by_blockchain
Error.PAY_ID_NOT_REGISTERED -> R.string.error_payid_not_registere
Error.PAY_ID_REQUEST_FAILED -> R.string.error_payid_request_failed
Error.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.error_address_invalid_or_unsupported
Error.ADDRESS_SAME_AS_WALLET -> R.string.error_address_same_as_wallet
Error.PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.send_error_payid_unsupported_by_blockchain
Error.PAY_ID_NOT_REGISTERED -> R.string.send_error_payid_not_registere
Error.PAY_ID_REQUEST_FAILED -> R.string.send_error_payid_request_failed
Error.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.send_error_address_invalid_or_unsupported
Error.ADDRESS_SAME_AS_WALLET -> R.string.send_error_address_same_as_wallet
else -> null
}
return if (resId == null) null else context.getString(resId, "", "")
@ -139,7 +139,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
fg.tvAmountCurrency.update(state.mainCurrency.currencySymbol)
(fg as? SendFragment)?.saveMainCurrency(state.mainCurrency.type)
val balanceText = fg.getString(R.string.send_balance,
val balanceText = fg.getString(R.string.send_balance_subtitle_format,
state.mainCurrency.currencySymbol,
state.viewBalanceValue)
fg.tvBalance.update(balanceText)
@ -173,7 +173,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
}
if (state.error == FeeAction.Error.REQUEST_FAILED) {
fg.showRetrySnackbar(fg.requireContext().getString(R.string.error_fee_request_failed)) {
fg.showRetrySnackbar(fg.requireContext().getString(R.string.send_error_fee_request_failed)) {
store.dispatch(FeeAction.RequestFee)
}
}
@ -186,7 +186,8 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
val mainLayout = fg.clReceiptContainer as ViewGroup
val totalLayout = fg.llTotal as ViewGroup
val totalTokenLayout = fg.flTotalTokenCrypto as ViewGroup
fun getString(id: Int): String = mainLayout.context.getString(id)
fun getString(id: Int, vararg formatStrings: String): String =
mainLayout.context.getString(id, *formatStrings)
val rough = getString(R.string.sign_rough)
fun roughOrEmpty(value: String): String = if (value == ReceiptReducer.EMPTY) value else "$rough $value"
@ -201,11 +202,9 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
val willSent = SpannableStringBuilder()
.bold { append(receipt.willSentCrypto) }.append(" ")
.append(receipt.symbols.crypto).append(" ")
.append(getString(R.string.send_total_will_be_sent))
totalLayout.tvWillBeSentValue.update(willSent.toString())
val willSent = getString(R.string.send_total_subtitle_format,
receipt.willSentCrypto, receipt.symbols.crypto)
totalLayout.tvWillBeSentValue.update(willSent)
}
ReceiptLayoutType.CRYPTO -> {
@ -235,18 +234,12 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
val willSent = SpannableStringBuilder()
.bold {
append(receipt.symbols.token)
append(" ")
append(receipt.willSentToken)
}.append(" ").append(getString(R.string.generic_and)).append(" ")
.bold {
append(receipt.symbols.crypto).append(" ")
append(receipt.willSentFeeCoin).append(" ")
}
.append(mainLayout.context.getString(R.string.send_total_will_be_sent))
totalLayout.tvWillBeSentValue.update(willSent.toString())
val willSent = getString(
R.string.send_total_subtitle_asset_format,
receipt.symbols.token ?: "", receipt.willSentToken,
receipt.symbols.crypto, receipt.willSentFeeCoin
)
totalLayout.tvWillBeSentValue.update(willSent)
}
ReceiptLayoutType.TOKEN_CRYPTO -> {
val receipt = state.tokenCrypto ?: return

View file

@ -74,7 +74,7 @@ sealed class WalletAction : Action {
data class CopyAddress(val context: Context) : WalletAction() {
object Success : WalletAction(), NotificationAction {
override val messageResource = R.string.notification_address_copied
override val messageResource = R.string.wallet_notification_address_copied
}
}

View file

@ -3,10 +3,7 @@ package com.tangem.tap.features.wallet.redux
import android.content.Intent
import android.net.Uri
import androidx.core.content.ContextCompat
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.SignatureCountValidator
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.*
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.commands.Card
import com.tangem.commands.common.network.Result
@ -218,22 +215,25 @@ private fun checkIfWarningNeeded(
private fun checkHashesCountOnline() {
if (store.state.walletState.hashesCountVerified != false) return
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) return
val card = store.state.globalState.scanNoteResponse?.card
if (card == null || preferencesStorage.wasCardScannedBefore(card.cardId)) return
val validator = store.state.globalState.scanNoteResponse?.walletManager
as? SignatureCountValidator
scope.launch {
val result = validator?.validateSignatureCount(card?.walletSignedHashes
?: 0)
val result = validator?.validateSignatureCount(card.walletSignedHashes ?: 0)
withContext(Dispatchers.Main) {
when (result) {
SimpleResult.Success -> store.dispatch(WalletAction.ConfirmHashesCount)
is SimpleResult.Failure -> store.dispatch(
WalletAction.ShowWarning(WarningType.CardSignedHashesBefore)
)
SimpleResult.Success -> {
store.dispatch(WalletAction.ConfirmHashesCount)
store.dispatch(WalletAction.SaveCardId)
}
is SimpleResult.Failure ->
if (result.error is BlockchainSdkError.SignatureCountNotMatched) {
store.dispatch(WalletAction.ShowWarning(WarningType.CardSignedHashesBefore))
}
}
}
}

View file

@ -68,7 +68,7 @@ class BalanceWidget(
R.id.tv_status_verified
} else {
fragment.tv_status_error.text =
fragment.getText(R.string.wallet_transaction_in_progress)
fragment.getText(R.string.wallet_balance_tx_in_progress)
R.id.group_error
}
showStatus(statusView)
@ -93,7 +93,7 @@ class BalanceWidget(
fragment.tv_amount.text = ""
fragment.tv_status_error_message.text = data.errorMessage
fragment.tv_status_error.text =
fragment.getString(R.string.wallet_blockchain_is_unreachable)
fragment.getString(R.string.wallet_balance_blockchain_unreachable)
showStatus(R.id.group_error)
fragment.tv_status_error_message.show(!data.errorMessage.isNullOrBlank())
@ -101,25 +101,25 @@ class BalanceWidget(
BalanceStatus.EmptyCard -> {
fragment.l_balance.hide()
fragment.l_balance_error.show()
fragment.tv_error_title.text = fragment.getText(R.string.wallet_empty_card)
fragment.tv_error_descriptions.text = fragment.getText(R.string.wallet_empty_card_description)
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_empty_card)
fragment.tv_error_descriptions.text = fragment.getText(R.string.wallet_error_empty_card_subtitle)
}
BalanceStatus.NoAccount -> {
fragment.l_balance.hide()
fragment.l_balance_error.show()
fragment.tv_error_title.text = fragment.getText(R.string.wallet_no_account)
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_no_account)
fragment.tv_error_descriptions.text =
fragment.getString(
R.string.wallet_no_account_description,
R.string.wallet_error_no_account_subtitle_format,
data.amountToCreateAccount, data.currencySymbol
)
}
BalanceStatus.UnknownBlockchain -> {
fragment.l_balance.hide()
fragment.l_balance_error.show()
fragment.tv_error_title.text = fragment.getText(R.string.wallet_unknown_blockchain_title)
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_unsupported_blockchain)
fragment.tv_error_descriptions.text =
fragment.getString(R.string.wallet_unknown_blockchain)
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
}
}
}

View file

@ -41,12 +41,12 @@ class PendingTransactionsAdapter
fun bind(transaction: PendingTransaction) {
val transactionDescriptionRes = when (transaction.type) {
PendingTransactionType.Incoming -> R.string.wallet_pending_transaction_incoming
PendingTransactionType.Outcoming -> R.string.wallet_pending_transaction_outcoming
PendingTransactionType.Incoming -> R.string.wallet_pending_tx_receiving
PendingTransactionType.Outcoming -> R.string.wallet_pending_tx_sending
}
val transactionAddressRes = when (transaction.type) {
PendingTransactionType.Incoming -> R.string.wallet_pending_transaction_incoming_address
PendingTransactionType.Outcoming -> R.string.wallet_pending_transaction_outcoming_address
PendingTransactionType.Incoming -> R.string.wallet_pending_tx_receiving_address_format
PendingTransactionType.Outcoming -> R.string.wallet_pending_tx_sending_address_format
}
val image = when (transaction.type) {
PendingTransactionType.Incoming -> R.drawable.ic_arrow_left

View file

@ -45,7 +45,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
setHasOptionsMenu(true)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
}
})
val inflater = TransitionInflater.from(requireContext())
@ -72,7 +72,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener {
store.dispatch(NavigationAction.PopBackTo())
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
}
btn_scan.setOnClickListener {
@ -95,7 +95,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
if (!state.showDetails) {
toolbar.menu.removeItem(R.id.details_menu)
} else if (toolbar.menu.findItem(R.id.details_menu) == null) {
toolbar.menu.add(R.menu.wallet, R.id.details_menu, NONE, R.string.details_toolbar_title)
toolbar.menu.add(R.menu.wallet, R.id.details_menu, NONE, R.string.details_title)
}
srl_wallet.setOnRefreshListener {
@ -149,9 +149,9 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
if (state.error == ErrorType.NoInternetConnection) {
srl_wallet?.isRefreshing = false
snackbar = Snackbar.make(
coordinator_wallet, getString(R.string.notification_no_internet),
coordinator_wallet, getString(R.string.wallet_notification_no_internet),
Snackbar.LENGTH_INDEFINITE
).setAction(getString(R.string.notification_no_internet_retry))
).setAction(getString(R.string.wallet_notification_no_internet_retry))
{ store.dispatch(WalletAction.LoadData) }
.also { it.show() }
}

View file

@ -28,7 +28,7 @@ class PayIdDialog(context: Context) : Dialog(context) {
store.dispatch(WalletAction.CreatePayId.EmptyField)
} else {
val payid = this.et_payid.text!!.toString() +
this.context.getString(R.string.wallet_pay_id_address)
this.context.getString(R.string.wallet_create_payid_domain)
store.dispatch(WalletAction.CreatePayId.CompleteCreatingPayId(payid))
}
}

View file

@ -28,7 +28,7 @@ class QrDialog(context: Context) : Dialog(context) {
} else {
this.tv_qr_dialog_header.show()
this.tv_qr_dialog_header.text = context.getString(
R.string.wallet_dialog_qr_code_header, currencyName
R.string.wallet_qr_title_format, currencyName
)
}
super.show()

View file

@ -10,8 +10,8 @@ import com.tangem.wallet.R
class WarningDialog(context: Context) : AlertDialog(context) {
private val dialog: AlertDialog = Builder(context)
.setTitle(context.getString(R.string.generic_warning))
.setPositiveButton(context.getString(R.string.general_ok)) { _, _ ->
.setTitle(context.getString(R.string.common_warning))
.setPositiveButton(context.getString(R.string.common_ok)) { _, _ ->
dismiss()
}.setOnDismissListener {
store.dispatch(WalletAction.SaveCardId)
@ -21,8 +21,8 @@ class WarningDialog(context: Context) : AlertDialog(context) {
fun show(warningType: WarningType) {
val messageRes = when (warningType) {
WarningType.CardSignedHashesBefore -> R.string.warning_card_signed_transactions
WarningType.DevCard -> R.string.wallet_warning_dev_card
WarningType.CardSignedHashesBefore -> R.string.alert_card_signed_transactions
WarningType.DevCard -> R.string.alert_developer_card
}
dialog.setMessage(dialog.context.getString(messageRes))
dialog.show()

View file

@ -65,12 +65,22 @@ class PreferencesStorage(applicationContext: Application) {
private fun restoreScannedCardIds(): String =
preferences.getString(SCANNED_CARDS_IDS_KEY, "") ?: ""
fun saveDisclaimerAccepted() {
preferences.edit().putBoolean(DISCLAIMER_ACCEPTED_KEY, true).apply()
}
fun wasDisclaimerAccepted(): Boolean {
return preferences.getBoolean(DISCLAIMER_ACCEPTED_KEY, false)
}
companion object {
private const val PREFERENCES_NAME = "tapPrefs"
private const val APP_CURRENCY_KEY = "appCurrency"
private const val FIAT_CURRENCIES_KEY = "fiatCurrencies"
private const val FIRST_LAUNCH_CHECK_KEY = "firstLaunchCheck"
private const val SCANNED_CARDS_IDS_KEY = "scannedCardIds"
private const val DISCLAIMER_ACCEPTED_KEY = "disclaimerAccepted"
}
}

View file

@ -19,7 +19,7 @@
android:ellipsize="middle"
android:fontFamily="sans-serif-medium"
android:paddingEnd="24dp"
android:text="@string/wallet_dialog_pay_id_button"
android:text="@string/wallet_create_payid"
android:textColor="@color/textGray"
android:textSize="17sp"
app:layout_constraintStart_toStartOf="parent"
@ -31,7 +31,7 @@
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:hint="@string/wallet_dialog_pay_id_hint"
android:hint="@string/wallet_create_payid_hint"
android:inputType="textNoSuggestions|textVisiblePassword"
android:paddingStart="4dp"
android:paddingEnd="4dp"
@ -46,7 +46,7 @@
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:paddingBottom="1dp"
android:text="@string/wallet_pay_id_address"
android:text="@string/wallet_create_payid_domain"
android:textColor="@color/darkGray4"
app:layout_constraintBottom_toBottomOf="@+id/et_payid"
app:layout_constraintEnd_toEndOf="parent"
@ -60,7 +60,7 @@
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:text="@string/wallet_dialog_pay_id_description"
android:text="@string/wallet_create_payid_info"
android:textColor="@color/darkGray1"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="parent"
@ -80,7 +80,7 @@
android:insetBottom="0dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:text="@string/wallet_dialog_pay_id_button"
android:text="@string/wallet_create_payid"
android:textColor="@color/blue"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"

View file

@ -49,7 +49,7 @@
android:insetBottom="0dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:text="@string/generic_done"
android:text="@string/common_done"
android:textColor="@color/blue"
android:textSize="14sp" />

View file

@ -22,7 +22,7 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:title="@string/details_toolbar_title" />
app:title="@string/details_title" />
</com.google.android.material.appbar.AppBarLayout>
@ -48,7 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="14dp"
android:text="@string/details_card_id"
android:text="@string/details_row_title_cid"
android:textColor="@color/darkGray6"
android:textSize="16sp"
@ -71,7 +71,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="14dp"
android:text="@string/details_issuer"
android:text="@string/details_row_title_issuer"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
@ -92,7 +92,8 @@
android:id="@+id/tv_signed_hashes_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/details_signed_hashes"
android:paddingBottom="7dp"
android:text="@string/details_row_title_signed_hashes"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
@ -108,18 +109,32 @@
app:layout_constraintTop_toBottomOf="@id/tv_issuer"
tools:text="48 hashes" />
<TextView
android:id="@+id/tv_disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="10dp"
android:drawablePadding="15dp"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes_title"
android:text="@string/disclaimer_title" />
<TextView
android:id="@+id/tv_settings_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginTop="22dp"
android:paddingBottom="4dp"
android:text="@string/details_settings"
android:text="@string/details_section_title_settings"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signed_hashes_title" />
app:layout_constraintTop_toBottomOf="@id/tv_disclaimer" />
<View
android:layout_width="match_parent"
@ -146,25 +161,19 @@
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="@string/details_currency"
android:text="@string/details_row_title_currency"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_settings_title" />
<!-- <androidx.constraintlayout.widget.Group-->
<!-- android:id="@+id/group_app_currency"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:constraint_referenced_ids="tv_app_currency_title, tv_app_currency" />-->
<TextView
android:id="@+id/tv_card_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:paddingBottom="4dp"
android:text="@string/details_card"
android:text="@string/details_section_title_card"
android:textAllCaps="true"
android:textColor="@color/colorSecondary"
android:textSize="13sp"
@ -197,7 +206,7 @@
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="7dp"
android:text="@string/details_manage_security"
android:text="@string/details_row_title_manage_security"
android:textColor="@color/darkGray6"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
@ -216,7 +225,7 @@
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_security_title"
android:text="@string/details_erase_wallet" />
android:text="@string/details_row_title_erase_wallet" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -20,7 +20,7 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/details_manage_security"
app:title="@string/details_row_title_manage_security"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24" />
</com.google.android.material.appbar.AppBarLayout>

View file

@ -0,0 +1,82 @@
<?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"
android:id="@+id/coordinator_details_confirm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/backgroundLightGray"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
style="@style/Widget.MaterialComponents.Toolbar.Surface"
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_baseline_arrow_back_24"
app:title="@string/disclaimer_title" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_details_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="33dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.core.widget.NestedScrollView
android:id="@+id/sv_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:fillViewport="true"
android:overScrollMode="never"
app:layout_constraintBottom_toTopOf="@id/btn_accept">
<TextView
android:id="@+id/tv_warning_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:paddingStart="16dp"
android:paddingEnd="24dp"
android:paddingBottom="40dp"
android:text="@string/disclaimer_text"
android:textAlignment="textStart"
android:textSize="16sp" />
</androidx.core.widget.NestedScrollView>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintGuide_percent="0.37" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_accept"
style="@style/TapButtonWithIcon"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="7dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="30dp"
android:text="@string/common_accept"
app:icon="@drawable/ic_send"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -54,7 +54,7 @@
android:layout_marginTop="100dp"
android:paddingStart="30dp"
android:paddingEnd="30dp"
android:text="@string/home_do_you_have_card"
android:text="@string/home_welcome"
android:textColor="@color/darkGray6"
android:textSize="29sp"
app:layout_constraintTop_toBottomOf="@id/iv_home_card" />

View file

@ -22,7 +22,7 @@
android:layout_height="?attr/actionBarSize"
app:menu="@menu/wallet"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:title="@string/wallet_toolbar_title" />
app:title="@string/wallet_title" />
</com.google.android.material.appbar.AppBarLayout>

View file

@ -49,7 +49,7 @@
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:paddingBottom="25dp"
android:text="@string/wallet_explore_address"
android:text="@string/wallet_address_button_explore"
android:textColor="@color/darkGray6"
android:textSize="14sp"
android:textStyle="bold"
@ -130,7 +130,7 @@
android:layout_height="wrap_content"
android:drawablePadding="9dp"
android:padding="16dp"
android:text="@string/wallet_create_payid"
android:text="@string/wallet_address_button_create_payid"
android:textColor="@color/darkGray6"
android:textSize="14sp"
android:textStyle="bold"

View file

@ -29,7 +29,7 @@
android:paddingStart="16dp"
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:text="@string/wallet_verified_balance"
android:text="@string/wallet_balance_verified"
android:textColor="@color/accent"
android:textSize="14sp"
android:visibility="gone"
@ -45,7 +45,7 @@
android:paddingStart="16dp"
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:text="@string/wallet_blockchain_is_unreachable"
android:text="@string/wallet_balance_blockchain_unreachable"
android:textColor="@color/warning"
android:textSize="14sp"
android:visibility="gone"
@ -81,7 +81,7 @@
android:paddingStart="16dp"
android:paddingTop="4dp"
android:paddingEnd="16dp"
android:text="@string/wallet_balance_is_loading"
android:text="@string/wallet_balance_loading"
android:textColor="@color/darkGray6"
android:textSize="13sp"
android:visibility="gone"

View file

@ -20,7 +20,7 @@
android:id="@+id/tv_error_title"
app:layout_constraintStart_toEndOf="@id/iv_balance_error"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/wallet_account_not_created"
tools:text="@string/wallet_error_no_account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"

View file

@ -24,7 +24,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:text="@string/send_total"
android:text="@string/send_total_label"
android:textSize="20sp"
android:textStyle="bold" />
@ -45,8 +45,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="end"
android:layout_marginTop="4dp"
android:text="@string/send_total_will_be_sent"
tools:text="@string/send_total_subtitle_format"
android:textColor="@color/darkGray1" />
</LinearLayout>
@ -62,7 +63,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:text="@string/send_total"
android:text="@string/send_total_label"
android:textColor="@color/darkGray1"
android:textSize="14sp"
android:textStyle="bold" />

View file

@ -11,7 +11,7 @@
android:id="@+id/tilAddressOrPayId"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/send_address_or_payid"
android:hint="@string/send_destination_hint"
app:boxBackgroundColor="@color/backgroundLightGray"
app:errorIconDrawable="@null"
app:layout_constraintEnd_toEndOf="parent"

View file

@ -11,7 +11,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/send_fee"
android:text="@string/send_network_fee_title"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/flExpandCollapse"
app:layout_constraintStart_toStartOf="parent"
@ -51,21 +51,21 @@
style="@style/ChipNetworkFee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_fee_low" />
android:text="@string/send_fee_picker_low" />
<com.google.android.material.chip.Chip
android:id="@+id/chipNormal"
style="@style/ChipNetworkFee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_fee_normal" />
android:text="@string/send_fee_picker_normal" />
<com.google.android.material.chip.Chip
android:id="@+id/chipPriority"
style="@style/ChipNetworkFee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_fee_priority" />
android:text="@string/send_fee_picker_priority" />
</com.google.android.material.chip.ChipGroup>
@ -75,7 +75,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:text="@string/send_fee_include"
android:text="@string/send_fee_include_description"
android:textSize="13sp" />
</LinearLayout>

View file

@ -12,7 +12,7 @@
android:id="@+id/tvReceiptAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_total_amount"
android:text="@string/send_amount_label"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -33,7 +33,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/send_total_fee"
android:text="@string/send_fee_label"
android:textColor="@color/darkGray1"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"

View file

@ -10,7 +10,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:text="@string/wallet_tokens"
android:text="@string/wallet_balance_tokens_title"
android:textColor="@color/darkGray1"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"

View file

@ -11,7 +11,7 @@
android:id="@+id/tv_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_set_maximum_amount"
android:text="@string/send_max_amount_label"
android:textColor="#F4F5F6"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"

View file

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/details_menu"
android:title="@string/details_toolbar_title"
android:title="@string/details_title"
android:icon="@drawable/ic_settings"
app:showAsAction="ifRoom" />
</menu>

View file

@ -2,129 +2,200 @@
<string name="app_name" translatable="false">Tangem Tap</string>
<string name="generic_done">Done</string>
<string name="generic_cancel">Cancel</string>
<string name="generic_retry">Retry</string>
<string name="generic_and">and</string>
<string name="generic_warning">Warning</string>
<string name="common_no">No</string>
<string name="common_save_changes">Save changes</string>
<string name="common_warning">Warning</string>
<string name="common_retry">Retry</string>
<string name="common_done">Done</string>
<string name="common_cancel">Cancel</string>
<string name="common_accept">Accept</string>
<!--iOS-->
<string name="common_camera_denied_alert_title">Camera access denied</string>
<string name="common_camera_denied_alert_message">You have not given access to your camera, please adjust your privacy settings</string>
<string name="common_camera_alert_button_settings">Settings</string>
<string name="tap_to_scan">Tap to scan</string>
<string name="tap_the_card">Tap the card</string>
<string name="tap_to_sign">Tap to sign</string>
<string name="tap_to_purge_wallet">Tap to purge wallet</string>
<string name="tap_to_create_wallet">Tap to create wallet</string>
<string name="tap_to_change_passcode">Tap to change passcode</string>
<string name="tap_to_change_access_code">Tap to change access code</string>
<string name="notification_address_copied">Address was successfully copied</string>
<string name="notification_no_internet">No internet connection</string>
<string name="notification_no_internet_retry">@string/generic_retry</string>
<string name="home_do_you_have_card">Welcome to Tangem.\nDo you have one of our cards?</string>
<string name="home_welcome">Welcome to Tangem.\nDo you have one of our cards?</string>
<string name="home_welcome_back">Welcome back to Tangem Tap. \nScan your card to start.</string>
<string name="home_button_yes">Yes. Scan it!</string>
<string name="home_button_scan">Scan card</string>
<string name="home_button_shop">Shop</string>
<string name="home_button_no_card">No</string>
<string name="home_ready_title">Get ready to tap your \ncard to the back of the \nphone.</string>
<string name="home_button_tapin">Tap in</string>
<string name="home_button_scan">Scan card</string>
<string name="home_button_no_card">@string/common_no</string>
<string name="wallet_toolbar_title" translatable="false">Tangem Tap</string>
<string name="wallet_title" translatable="false">@string/app_name</string>
<string name="wallet_button_scan">Scan</string>
<string name="wallet_button_send">Send</string>
<string name="wallet_button_create_wallet">Create Wallet</string>
<string name="wallet_explore_address">Explore address</string>
<string name="wallet_choice_wallet_option_title">Choice wallet option</string>
<string name="wallet_address_button_explore">Explore address</string>
<string name="wallet_address_button_create_payid">Create PayID</string>
<string name="wallet_balance_verified">Verified Balance</string>
<string name="wallet_balance_blockchain_unreachable">Blockchain is unreachable</string>
<string name="wallet_balance_loading">Balance is loading…</string>
<string name="wallet_balance_tx_in_progress">Transaction is in progress</string>
<string name="wallet_balance_tokens_title">Tokens</string>
<string name="wallet_balance_token_title">Token</string>
<string name="wallet_error_unsupported_blockchain">This card is not supported</string>
<string name="wallet_error_unsupported_blockchain_subtitle">Your Tangem card was made to work with a different application. Please see the name and instructions on your card, and install the correct app.</string>
<string name="wallet_error_empty_card">Empty Card</string>
<string name="wallet_error_empty_card_subtitle">Create wallet to start using Tangem card</string>
<string name="wallet_error_no_account">Account is not created</string>
<string name="wallet_error_no_account_subtitle_format">Load %1s+ %2s to create account</string>
<string name="wallet_pending_tx_receiving">Receiving\u0020</string>
<string name="wallet_pending_tx_sending">Sending\u0020</string>
<string name="wallet_pending_tx_receiving_address_format"> from %s </string>
<string name="wallet_pending_tx_sending_address_format"> to %s </string>
<string name="wallet_create_payid">Create PayID</string>
<string name="wallet_verified_balance">Verified Balance</string>
<string name="wallet_blockchain_is_unreachable">Blockchain is unreachable</string>
<string name="wallet_transaction_in_progress">Transaction is in progress</string>
<string name="wallet_unknown_blockchain">Your Tangem card was made to work with a different application. Please see the name and instructions on your card, and install the correct app.</string>
<string name="wallet_unknown_blockchain_title">Uh oh!</string>
<string name="wallet_balance_is_loading">Balance is loading…</string>
<string name="wallet_account_not_created">Account is not created</string>
<string name="wallet_empty_card">Empty Card</string>
<string name="wallet_empty_card_description">Create wallet to start using Tangem card</string>
<string name="wallet_no_account">Account is not created</string>
<string name="wallet_no_account_description">Load %1s+ %2s to create account</string>
<string name="wallet_tokens">Tokens</string>
<string name="wallet_pending_transaction_incoming">Receiving\u0020</string>
<string name="wallet_pending_transaction_outcoming">Sending\u0020</string>
<string name="wallet_pending_transaction_incoming_address"> from %s </string>
<string name="wallet_pending_transaction_outcoming_address"> to %s </string>
<string name="wallet_dialog_pay_id_button">Create PayID</string>
<string name="wallet_create_payid_card_format">Card: %s</string>
<string name="wallet_create_payid_empty">Enter desired PayID first</string>
<string name="wallet_dialog_pay_id_hint">PayID name</string>
<string name="wallet_pay_id_address" translatable="false">$payid.tangem.com</string>
<string name="wallet_dialog_pay_id_description">Your PayID is information unique to you, like your phone number, email or ABN.</string>
<string name="wallet_dialog_qr_code_header">%s wallet</string>
<string name="wallet_create_payid_hint">PayID name</string>
<string name="wallet_create_payid_button_title">Create</string>
<string name="wallet_create_payid_domain" translatable="false">$payid.tangem.com</string>
<string name="wallet_create_payid_info">Your PayID is information unique to you, like your phone number, email or ABN.</string>
<string name="wallet_create_payid_error_already_created">This PayID already exists. Try a different one.</string>
<string name="wallet_create_payid_error_message">Error response while creating PayID</string>
<string name="wallet_create_payid_success_message">PayID created successfully and copied to clipboard</string>
<string name="wallet_warning_dev_card">The card you scanned is a development card. Don\'t accept it as a payment.</string>
<string name="warning_card_signed_transactions">Warning: This card has been already topped up and signed transactions in the past.
<string name="wallet_qr_title_format">%s wallet</string>
<string name="wallet_notification_address_copied">Address was successfully copied</string>
<string name="wallet_notification_no_internet">No internet connection</string>
<string name="wallet_notification_no_internet_retry">@string/common_retry</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_card_signed_transactions">Warning: This card has been already topped up and signed transactions in the past.
Consider immediate withdrawal of all funds if you have received this card from an untrusted source.</string>
<string name="alert_unsupported_card">This card it is not designed to work with Tangem Tap</string>
<string name="alert_old_device_this_card">You may experience NFC problems with some iPhone 7/7+ during the extraction</string>
<string name="error_payid_already_created">This PayID already exists. Try a different one.</string>
<string name="error_creating_payid">Error response while creating PayID.</string>
<string name="error_card_for_different_app">This card it is not designed to work with Tangem Tap</string>
<string name="error_unknown">Unknown error</string>
<string name="error_payid_verification_failed">PayID verification failed</string>
<string name="error_payid_unsupported_by_blockchain">PayID unsupported by blockchain</string>
<string name="error_payid_not_registere">PayID not registered</string>
<string name="error_payid_request_failed">PayID request failed</string>
<string name="error_address_invalid_or_unsupported">Address is invalid or unsupported by blockchain</string>
<string name="error_address_same_as_wallet">Address is the same as wallet address</string>
<string name="error_fee_request_failed">Network fee request is failed</string>
<string name="error_insufficient_balance">Insufficient balance</string>
<string name="error_blockchain_internal">Blockchain internal error</string>
<string name="amount_exceeds_balance">Amount Exceeds Balance</string>
<string name="fee_exceeds_balance">Fee Exceeds Balance</string>
<string name="total_exceeds_balance">Total Exceeds Balance</string>
<string name="invalid_amount_value">Invalid Amount</string>
<string name="invalid_fee_value">Invalid Fee</string>
<string name="dust_amount">Minimum amount is %s</string>
<string name="dust_change">Change is too small</string>
<string name="create_account_underfunded">Target account is not created. Send more than %1$s %2$s to create</string>
<string name="send_error_unknown">Unknown error</string>
<string name="send_error_payid_verification_failed">PayID verification failed</string>
<string name="send_error_payid_unsupported_by_blockchain">PayID unsupported by blockchain</string>
<string name="send_error_payid_not_registere">PayID not registered</string>
<string name="send_error_payid_request_failed">PayID request failed</string>
<string name="send_error_address_invalid_or_unsupported">Address is invalid or unsupported by blockchain</string>
<string name="send_error_address_same_as_wallet">Address is the same as wallet address</string>
<string name="send_error_fee_request_failed">Network fee request is failed</string>
<string name="send_error_insufficient_balance">Insufficient balance</string>
<string name="send_error_blockchain_internal">Blockchain internal error</string>
<string name="send_error_amount_exceeds_balance">Amount Exceeds Balance</string>
<string name="send_error_fee_exceeds_balance">Fee Exceeds Balance</string>
<string name="send_error_total_exceeds_balance">Total Exceeds Balance</string>
<string name="send_error_invalid_amount">Invalid Amount</string>
<string name="send_error_invalid_fee_value">Invalid Fee</string>
<string name="send_error_dust_amount_format">Minimum amount is %s</string>
<string name="send_error_dust_change">Change is too small</string>
<string name="send_error_no_target_accout">Target account is not created. Send more than %1$s %2$s to create</string>
<string name="send_title">Send</string>
<string name="send_address_or_payid">Address or PayID</string>
<string name="send_fee">Network fee</string>
<string name="send_fee_include">Include fee</string>
<string name="send_fee_low">Low</string>
<string name="send_fee_normal">Normal</string>
<string name="send_fee_priority">Priority</string>
<string name="send_btn_send">Send</string>
<string name="send_total">Total</string>
<string name="send_total_amount">Amount</string>
<string name="send_total_fee">Fee</string>
<string name="send_total_will_be_sent">will be sent</string>
<string name="send_balance">Balance: %1s %2s</string>
<string name="send_set_maximum_amount">Maximum amount</string>
<string name="send_transaction_complete">Transaction was signed and sent to the blockchain</string>
<string name="send_destination_hint">Address or PayID</string>
<string name="send_network_fee_title">Network fee</string>
<string name="send_fee_include_description">Include fee</string>
<string name="send_fee_picker_low">Low</string>
<string name="send_fee_picker_normal">Normal</string>
<string name="send_fee_picker_priority">Priority</string>
<string name="send_btn_send">@string/send_title</string>
<string name="send_total_label">Total</string>
<string name="send_amount_label">Amount</string>
<string name="send_fee_label">Fee</string>
<string name="send_total_subtitle_format">%1s %2s will be sent</string>
<string name="send_total_subtitle_fiat_format">≈ %1s (inc. fee: %2s)</string>
<string name="send_total_subtitle_asset_format">%1s %2s and %3s %4s will be sent</string>
<string name="send_balance_subtitle_format">Balance: %1s %2s</string>
<string name="send_max_amount_label">Maximum amount</string>
<string name="send_transaction_success">Transaction was signed and sent to the blockchain</string>
<string name="details_toolbar_title">Details</string>
<string name="details_title">Details</string>
<string name="details_notification_erase_wallet_not_allowed">Card settings prohibits from erasing wallet</string>
<string name="details_notification_erase_wallet_not_possible">You balance on this wallet is not zero, or you have unconfirmed transactions</string>
<string name="details_notification_security_option_already_active">This is the currently active option</string>
<string name="details_card_id">Card ID</string>
<string name="details_issuer">Issuer</string>
<string name="details_signed_hashes">Signed</string>
<string name="details_settings">Settings</string>
<string name="details_currency">App currency</string>
<string name="details_card">Card</string>
<string name="details_validate_card">Validate card</string>
<string name="details_manage_security">Manage security</string>
<string name="details_erase_wallet">Erase wallet</string>
<string name="details_save_changes">Save changes</string>
<string name="details_row_title_cid">Card ID</string>
<string name="details_row_title_issuer">Issuer</string>
<string name="details_row_title_signed_hashes">Signed</string>
<string name="details_row_subtitle_signed_hashes_format">%s hashes</string>
<string name="details_row_title_currency">App currency</string>
<string name="details_section_title_settings">Settings</string>
<string name="details_section_title_card">Card</string>
<string name="details_row_title_validate">Validate card</string>
<string name="details_row_title_manage_security">Manage security</string>
<string name="details_row_title_erase_wallet">Erase wallet</string>
<string name="details_continue">Continue</string>
<string name="details_manage_security_long_tap">Long Tap</string>
<string name="details_manage_security_passcode">Passcode</string>
<string name="details_manage_security_access_code">Access Code</string>
<string name="details_manage_security_long_tap_description">This mechanism protects against proximity attack on a card. It will enforce a delay between reception and execution of a command. After the first signed transaction this phone will be linked with the card and transactions will be signed immediately.</string>
<string name="details_manage_security_passcode_description">Before execution of any command entailing a change of the card state you will have to enter the passcode.</string>
<string name="details_manage_security_access_code_description">You will have to submit the correct access code before scanning the card.</string>
<string name="details_erase_wallet_warning">This action is irreversible. If, after deleting the wallet, someone sends funds to it, then you will not be able to withdraw them.</string>
<string name="details_manage_security_warning">If you forget the code, you will lose the ability to use the card. There is no way to recover or change your code if you lose it.
</string>
<string name="details_erase_wallet_warning">This action is irreversible. If, after deleting the wallet, someone sends funds to it, then you will not be able to withdraw them.</string>
<string name="details_security_management_warning">If you forget the code, you will lose the ability to use the card. There is no way to recover or change your code if you lose it.</string>
<string name="initial_message_scan_header">Tap to scan</string>
<string name="initial_message_tap_header">Tap the card</string>
<string name="initial_message_sign_header">Tap to sign</string>
<string name="initial_message_purge_wallet_body">Tap to erase wallet</string>
<string name="initial_message_create_wallet_body">Tap to create wallet</string>
<string name="initial_message_change_passcode_body">Tap to change the passcode</string>
<string name="initial_message_change_access_code_body">Tap to change the access code</string>
<string name="payid_service_error_loading">Invalid PayID</string>
<string name="disclaimer_text">Legal Disclaimer
\n
\n1. Tangem Tap application (Software)
\n
\nThe Software is intended for usage only with Tangem hardware wallets (Cards) via NFC interface. The Software DOES NOT:
\n
\na) Generate, store, transmit, or have access to private (secret) cryptographic keys to blockchain wallets holding digital assets, including crypto-currency.
\n
\nb) Generate, store, transmit, or have access to secret keys, passwords, passphrases, recovery phrases that can be used to restore or to copy private (secret) keys to blockchain wallets holding digital assets, including crypto-currency.
\n
\nc) Provide exchange, trading, investment services on behalf of Tangem AG.
\n
\n2. Risks related to the use of Software
\n
\nTangem will not be responsible for any losses, damages or claims arising from events falling within the scope of the following five categories:
\n
\na) Mistakes made by the user of any cryptocurrency-related software or service, e.g., forgotten passwords, payments sent to wrong addresses, and accidental deletion of blockchain wallets on Cards.
\n
\nb) Problems of Software and/or any blockchain- or cryptocurrency- related software or service, e.g., corrupted files, incorrectly constructed transactions, unsafe cryptographic libraries, malware.
\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.
\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
\n3. Trading and Investment risks
\n
\nThere is considerable exposure to risk in any crypto-currency or other digital asset exchange transaction. Any transaction involving currencies involves risks including, but not limited to, the potential for changing economic conditions that may substantially affect the price or liquidity of a currency. Investments in crypto-currency exchange speculation may also be susceptible to sharp rises and falls as the relevant market values fluctuate. It is for this reason that when speculating in such markets it is advisable to use only risk capital.
\n
\n4. Electronic Trading Risks
\n
\nBefore you engage in transactions using an electronic system, you should carefully review the rules and regulations of the exchanges offering the system and/or listing the instruments you intend to trade. Online trading has inherent risk due to system response and access times that may vary due to market conditions, system performance, and other factors. You should understand these and additional risks before trading.
\n
\n5. Compliance with tax obligations
\n
\nThe users of the Software are solely responsible to determinate what, if any, taxes apply to their crypto-currency transactions. The owners of, or contributors to, the Software are NOT responsible for determining the taxes that apply to crypto-currency transactions.
\n
\n6. No warranties
\n
\nThe Software is provided on an \“as is\” basis without any warranties of any kind regarding the Software and/or any content, data, materials and/or services provided on the Software.
\n
\n7. Limitation of liability
\n
\nUnless otherwise required by law, in no event shall the owners of, or contributors to, the Software be liable for any damages of any kind, including, but not limited to, loss of use, loss of profits, or loss of data arising out of or in any way connected with the use of the Software. In no way are the owners of, or contributors to, the Software responsible for the actions, decisions, or other behavior taken or not taken by you in reliance upon the Software.
\n
\n8. Last amendment
\n
\nThis disclaimer was amended for the last time on October 1st, 2020.</string>
<string name="disclaimer_title">Terms of service</string>>
</resources>