Updated on 2026-08-14
This commit is contained in:
parent
2d98489526
commit
a75226b865
9 changed files with 222 additions and 20 deletions
|
|
@ -4,6 +4,11 @@ apply plugin: 'kotlin-kapt'
|
|||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
ext.configVar = [
|
||||
configEnvironment: "CONFIG_ENVIRONMENT",
|
||||
testActionEnabled: "TEST_ACTION_ENABLED",
|
||||
]
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
defaultConfig {
|
||||
|
|
@ -13,19 +18,14 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField 'Boolean', configVar.testActionEnabled, 'false'
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
viewBinding true
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
debuggable false
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.debug
|
||||
buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"prod\"'
|
||||
}
|
||||
debug {
|
||||
debuggable true
|
||||
minifyEnabled false
|
||||
|
|
@ -34,14 +34,24 @@ android {
|
|||
firebaseCrashlytics {
|
||||
mappingFileUploadEnabled false
|
||||
}
|
||||
buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"dev\"'
|
||||
buildConfigField 'String', configVar.configEnvironment, '\"dev\"'
|
||||
buildConfigField 'Boolean', configVar.testActionEnabled, 'true'
|
||||
}
|
||||
debug_beta {
|
||||
initWith release
|
||||
debuggable false
|
||||
versionNameSuffix "-beta"
|
||||
applicationIdSuffix ".debug"
|
||||
buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"prod\"'
|
||||
buildConfigField 'String', configVar.configEnvironment, '\"prod\"'
|
||||
buildConfigField 'Boolean', configVar.testActionEnabled, 'false'
|
||||
}
|
||||
release {
|
||||
debuggable false
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.debug
|
||||
buildConfigField 'String', configVar.configEnvironment, '\"prod\"'
|
||||
buildConfigField 'Boolean', configVar.testActionEnabled, 'false'
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
is AppDialog.SimpleOkDialogRes -> SimpleOkDialog.create(state.dialog, context)
|
||||
is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context)
|
||||
is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context)
|
||||
is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context)
|
||||
is TwinCardsAction.Wallet.ShowInterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context)
|
||||
is WalletConnectDialog.UnsupportedCard ->
|
||||
SimpleAlertDialog.create(
|
||||
|
|
|
|||
75
app/src/main/java/com/tangem/tap/common/TestActions.kt
Normal file
75
app/src/main/java/com/tangem/tap/common/TestActions.kt
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package com.tangem.tap.common
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.widget.LinearLayoutCompat
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.tap.common.extensions.dispatchDialogHide
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.BuildConfig
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
||||
object TestActions {
|
||||
|
||||
// It used only for the test actions in debug or debug_beta builds
|
||||
var testAmountInjectionForWalletManagerEnabled = false
|
||||
|
||||
/**
|
||||
* @param isTestView - true must be used if you want to show or hide your view depends on BuildConfig
|
||||
*/
|
||||
fun initFor(view: View, actions: List<TestAction>, isTestView: Boolean = false) {
|
||||
if (isTestView) view.show(BuildConfig.TEST_ACTION_ENABLED)
|
||||
if (!BuildConfig.TEST_ACTION_ENABLED) return
|
||||
|
||||
view.setOnClickListener {
|
||||
store.dispatchDialogShow(AppDialog.TestActionsDialog(actions))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias TestAction = Pair<String, () -> Unit>
|
||||
|
||||
class TestActionsBottomSheetDialog(
|
||||
private val appDialog: AppDialog.TestActionsDialog,
|
||||
context: Context
|
||||
) : BottomSheetDialog(context) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContentView(createContentView())
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
behavior.peekHeight = 400
|
||||
setOnCancelListener {
|
||||
store.dispatchDialogHide()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createContentView(): View {
|
||||
val actionButtons = mutableListOf<View>()
|
||||
appDialog.actionsList.forEach { (actionName, action) ->
|
||||
val view = Button(context).apply {
|
||||
text = actionName
|
||||
setOnClickListener {
|
||||
action()
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
actionButtons.add(view)
|
||||
}
|
||||
|
||||
return LinearLayoutCompat(context).apply {
|
||||
orientation = LinearLayoutCompat.VERTICAL
|
||||
actionButtons.forEach { addView(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.tangem.blockchain.common.BlockchainSdkError
|
|||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
|
|
@ -20,8 +21,9 @@ import timber.log.Timber
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
suspend fun WalletManager.safeUpdate(): Result<Wallet> = try {
|
||||
if (isDemoWallet()) {
|
||||
if (isDemoWallet() || TestActions.testAmountInjectionForWalletManagerEnabled) {
|
||||
delay(500)
|
||||
TestActions.testAmountInjectionForWalletManagerEnabled = false
|
||||
Result.Success(wallet)
|
||||
} else {
|
||||
update()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.tap.common.TestAction
|
||||
import com.tangem.tap.features.wallet.redux.AddressData
|
||||
import com.tangem.tap.features.wallet.redux.Currency
|
||||
|
||||
|
|
@ -17,4 +18,8 @@ sealed class AppDialog : StateDialog {
|
|||
val currency: Currency,
|
||||
val addressData: AddressData,
|
||||
) : AppDialog()
|
||||
|
||||
data class TestActionsDialog(
|
||||
val actionsList: List<TestAction>
|
||||
) : AppDialog()
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import com.tangem.tap.common.compose.ComposeDialogManager
|
|||
import com.tangem.tap.common.compose.ToggledRippleTheme
|
||||
import com.tangem.tap.common.compose.keyboardAsState
|
||||
import com.tangem.tap.common.moduleMessage.ModuleMessageConverter
|
||||
import com.tangem.tap.features.tokens.addCustomToken.compose.test.TestAddCustomTokenActions
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
|
|
@ -51,7 +52,7 @@ fun AddCustomTokenScreen(state: MutableState<AddCustomTokenState>) {
|
|||
LazyColumn(
|
||||
contentPadding = PaddingValues(bottom = 90.dp)
|
||||
) {
|
||||
item { AddCustomTokenDebugActions() }
|
||||
item { TestAddCustomTokenActions() }
|
||||
item {
|
||||
Surface(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tap.features.tokens.addCustomToken.compose
|
||||
package com.tangem.tap.features.tokens.addCustomToken.compose.test
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Button
|
||||
|
|
@ -25,8 +25,8 @@ import timber.log.Timber
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun AddCustomTokenDebugActions() {
|
||||
if (!BuildConfig.DEBUG) return
|
||||
fun TestAddCustomTokenActions() {
|
||||
if (!BuildConfig.TEST_ACTION_ENABLED) return
|
||||
|
||||
Column() {
|
||||
// deep test
|
||||
|
|
@ -15,6 +15,7 @@ import by.kirich1409.viewbindingdelegate.viewBinding
|
|||
import com.squareup.picasso.Picasso
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.tap.common.SnackbarHandler
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -24,6 +25,7 @@ import com.tangem.tap.features.wallet.models.PendingTransaction
|
|||
import com.tangem.tap.features.wallet.redux.*
|
||||
import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
|
||||
import com.tangem.tap.features.wallet.ui.test.TestWalletDetails
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.FragmentWalletDetailsBinding
|
||||
|
|
@ -68,12 +70,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
|
|||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||
binding.toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
|
||||
|
||||
setupTransactionsRecyclerView()
|
||||
setupButtons()
|
||||
setupTestActionButton()
|
||||
}
|
||||
|
||||
|
||||
private fun setupTransactionsRecyclerView() = with(binding) {
|
||||
pendingTransactionAdapter = PendingTransactionsAdapter()
|
||||
rvPendingTransaction.layoutManager = LinearLayoutManager(requireContext())
|
||||
|
|
@ -91,6 +92,15 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
|
|||
btnSell.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Sell) }
|
||||
}
|
||||
|
||||
private fun setupTestActionButton() {
|
||||
view?.findViewById<View>(R.id.l_balance)?.let { view ->
|
||||
TestActions.initFor(
|
||||
view = view,
|
||||
actions = TestWalletDetails.solanaRentExemptWarning()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun newState(state: WalletState) {
|
||||
if (activity == null || view == null) return
|
||||
if (state.selectedCurrency == null) return
|
||||
|
|
@ -111,11 +121,13 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
|
|||
|
||||
binding.srlWalletDetails.setOnRefreshListener {
|
||||
if (selectedWallet.currencyData.status != BalanceStatus.Loading) {
|
||||
store.dispatch(
|
||||
WalletAction.LoadWallet(
|
||||
blockchain = BlockchainNetwork(selectedWallet.currency.blockchain, selectedWallet.currency.derivationPath, emptyList())
|
||||
store.dispatch(WalletAction.LoadWallet(
|
||||
blockchain = BlockchainNetwork(
|
||||
selectedWallet.currency.blockchain,
|
||||
selectedWallet.currency.derivationPath,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +175,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
|
|||
}
|
||||
|
||||
private fun handleNotEnoughFundsOnMainCurrency(selectedWalletData: WalletData) = with(binding) {
|
||||
if (selectedWalletData.currency.isBlockchain()) return@with
|
||||
|
||||
if (selectedWalletData.shouldShowCoinAmountWarning()) {
|
||||
val blockchainName = selectedWalletData.currency.blockchain.fullName
|
||||
val warningMessage = requireContext().getString(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tangem.tap.features.wallet.ui.test
|
||||
|
||||
import com.tangem.blockchain.blockchains.solana.SolanaWalletManager
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.tap.common.TestAction
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.domain.tokens.BlockchainNetwork
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
import java.math.BigDecimal
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class TestWalletDetails {
|
||||
companion object {
|
||||
fun solanaRentExemptWarning(): List<TestAction> {
|
||||
val checker = SolanaRentWarningActionEmitter()
|
||||
return listOf(
|
||||
"BALANCE = 0.0" to { checker.setZeroBalance() },
|
||||
"BALANCE < 0.00089088" to { checker.setLessThanRentExempt() },
|
||||
"BALANCE > 0.00089088" to { checker.setMoreThanRentExempt() },
|
||||
"BALANCE = 0.00089087" to { checker.setLessThanRentExemptByOne() },
|
||||
"BALANCE = 0.00089088 (rent exempt)" to { checker.setForRentExemptBarrier() },
|
||||
"BALANCE = 0.00089089" to { checker.setMoreThanRentExemptByOne() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SolanaRentWarningActionEmitter {
|
||||
|
||||
private val zero = BigDecimal.ZERO
|
||||
private val one = BigDecimal(0.00000001)
|
||||
private val rentExemptBarrier = BigDecimal(0.00089088)
|
||||
private val lessThanRentExemptByOne = rentExemptBarrier.minus(one)
|
||||
private val moreThanRentExemptByOne = rentExemptBarrier.plus(one)
|
||||
private val moreThanRentExempt = rentExemptBarrier.plus(Random.nextDouble().toBigDecimal())
|
||||
private val lessThanRentExempt = rentExemptBarrier
|
||||
.minus(Random.nextDouble(0.0, rentExemptBarrier.minus(one).toDouble()).toBigDecimal())
|
||||
|
||||
fun setZeroBalance() {
|
||||
setBalance(zero)
|
||||
}
|
||||
|
||||
fun setForRentExemptBarrier() {
|
||||
setBalance(rentExemptBarrier)
|
||||
}
|
||||
|
||||
fun setLessThanRentExemptByOne() {
|
||||
setBalance(lessThanRentExemptByOne)
|
||||
}
|
||||
|
||||
fun setMoreThanRentExemptByOne() {
|
||||
setBalance(moreThanRentExemptByOne)
|
||||
}
|
||||
|
||||
fun setMoreThanRentExempt() {
|
||||
setBalance(moreThanRentExempt)
|
||||
}
|
||||
|
||||
fun setLessThanRentExempt() {
|
||||
setBalance(lessThanRentExempt)
|
||||
}
|
||||
|
||||
private fun setBalance(value: BigDecimal) {
|
||||
val amount = Amount(getBlockchain()).copy(value = value)
|
||||
getWalletManager().apply {
|
||||
TestActions.testAmountInjectionForWalletManagerEnabled = true
|
||||
wallet.setAmount(amount)
|
||||
}
|
||||
store.dispatch(WalletAction.LoadData)
|
||||
}
|
||||
|
||||
private fun getWalletManager(): SolanaWalletManager {
|
||||
return store.state.walletState.getWalletManager(BlockchainNetwork(
|
||||
blockchain = getBlockchain(),
|
||||
card = scanResponse().card
|
||||
)) as SolanaWalletManager
|
||||
}
|
||||
|
||||
private fun getBlockchain(): Blockchain = when {
|
||||
scanResponse().card.isTestCard -> Blockchain.SolanaTestnet
|
||||
else -> Blockchain.Solana
|
||||
}
|
||||
|
||||
private fun scanResponse(): ScanResponse {
|
||||
return store.state.globalState.scanResponse ?: throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue