diff --git a/app/build.gradle b/app/build.gradle index 10d64081b7..cfc98ae2b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,6 +38,7 @@ android { } debug_beta { initWith release + debuggable true versionNameSuffix "-beta" applicationIdSuffix ".debug" buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"prod\"' diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt index d470ae2bf6..be71883ecc 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Picasso.kt @@ -15,9 +15,8 @@ fun Picasso.loadCurrenciesIcon( imageView: ImageView, textView: TextView, token: Token? = null, - blockchain: Blockchain?, + blockchain: Blockchain, ) { - val blockchain = blockchain ?: Blockchain.Ethereum val url = if (token != null) { IconsUtil.getTokenIconUri(blockchain, token) diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt index eb69c1066a..9a6735ae2e 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/CurrenciesRepository.kt @@ -42,12 +42,12 @@ class CurrenciesRepository(val context: Application) { } fun saveAddedTokens(cardId: String, tokens: Collection) { - saveTokens(cardId, loadSavedTokens(cardId) + tokens) + saveTokens(cardId, loadSavedTokens(cardId) + tokens.distinct()) } fun saveAddedBlockchain(cardId: String, blockchain: Blockchain) { val blockchains = loadSavedBlockchains(cardId) + blockchain - saveBlockchains(cardId, blockchains) + saveBlockchains(cardId, blockchains.distinct()) } fun removeToken(cardId: String, token: Token) { @@ -79,7 +79,7 @@ class CurrenciesRepository(val context: Application) { } private fun saveTokens(cardId: String, tokens: List) { - val json = tokensAdapter.toJson(tokens.map { TokenDao.fromToken(it) }.distinct()) + val json = tokensAdapter.toJson(tokens.distinct().map { TokenDao.fromToken(it) }) context.rewriteFile(json, getFileNameForTokens(cardId)) } @@ -93,7 +93,7 @@ class CurrenciesRepository(val context: Application) { } private fun saveBlockchains(cardId: String, blockchains: List) { - val json = blockchainsAdapter.toJson(blockchains) + val json = blockchainsAdapter.toJson(blockchains.distinct()) context.rewriteFile(json, getFileNameForBlockchains(cardId)) } diff --git a/app/src/main/java/com/tangem/tap/domain/twins/CreateSecondTwinWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/CreateSecondTwinWalletTask.kt index 966fe4f1d1..a1436169f6 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/CreateSecondTwinWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/CreateSecondTwinWalletTask.kt @@ -6,12 +6,13 @@ import com.tangem.common.KeyPair import com.tangem.common.card.EllipticCurve import com.tangem.common.core.CardSession import com.tangem.common.core.CardSessionRunnable -import com.tangem.common.core.TangemSdkError +import com.tangem.common.core.TangemError import com.tangem.common.extensions.hexToBytes import com.tangem.operations.wallet.CreateWalletCommand import com.tangem.operations.wallet.CreateWalletResponse import com.tangem.operations.wallet.PurgeWalletCommand import com.tangem.tap.domain.extensions.getSingleWallet +import com.tangem.wallet.R class CreateSecondTwinWalletTask( private val firstPublicKey: String, @@ -25,7 +26,7 @@ class CreateSecondTwinWalletTask( val publicKey = card?.getSingleWallet()?.publicKey if (publicKey != null) { if (!card.cardId.startsWith(TwinsHelper.getPairCardSeries(firstCardId) ?: "")) { - callback(CompletionResult.Failure(TangemSdkError.WrongCardType())) + callback(CompletionResult.Failure(WrongTwinCard())) return } @@ -65,4 +66,10 @@ class CreateSecondTwinWalletTask( } } } + + private class WrongTwinCard : TangemError { + override val code: Int = 50005 + override var customMessage: String = code.toString() + override val messageResId = R.string.twins_wrong_card_error + } } diff --git a/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt b/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt index 7ec70e8d17..2d8050dbdc 100644 --- a/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt +++ b/app/src/main/java/com/tangem/tap/features/feedback/FeedbackManager.kt @@ -114,6 +114,7 @@ class AdditionalEmailInfo { // wallets internal val walletsInfo = mutableListOf() + internal val tokens = mutableMapOf>() internal var onSendErrorWalletInfo: EmailWalletInfo? = null var signedHashesCount: String = "" @@ -146,6 +147,7 @@ class AdditionalEmailInfo { fun setWalletsInfo(walletManagers: List) { walletsInfo.clear() + tokens.clear() walletManagers.forEach { manager -> walletsInfo.add( EmailWalletInfo( @@ -155,6 +157,9 @@ class AdditionalEmailInfo { host = manager.currentHost ) ) + if (manager.cardTokens.isNotEmpty()) { + tokens[manager.wallet.blockchain] = manager.cardTokens + } } } @@ -308,6 +313,14 @@ class FeedbackEmail : EmailData { } appendBlankLine(builder) + infoHolder.tokens.forEach { tokens -> + appendDelimiter(builder) + builder.appendKeyValue("Blockchain", tokens.key.fullName) + builder.appendKeyValue("Tokens", tokens.value.map { "${it.name} - ${it.symbol}" }.toString()) + } + appendDelimiter(builder) + appendBlankLine(builder) + // appendKeyValue("Outputs count", infoHolder.outputsCount) builder.appendKeyValue("Phone model", infoHolder.phoneModel) builder.appendKeyValue("OS version", infoHolder.osVersion) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt index 0020137a82..62d98c1f69 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/dialog/CreateWalletInterruptDialog.kt @@ -15,9 +15,8 @@ class CreateWalletInterruptDialog { companion object { fun create(state: TwinCardsAction.Wallet.ShowInterruptDialog, context: Context): AlertDialog { return MaterialAlertDialogBuilder(context) - .setMessage(R.string.twins_recreate_alert) - .setPositiveButton(R.string.common_ok) { _, _ -> state.onOk() } - .setNegativeButton(R.string.common_cancel) { _, _ -> } + .setMessage(R.string.onboarding_twin_exit_warning) + .setPositiveButton(R.string.warning_button_ok) { _, _ -> } .setOnDismissListener { store.dispatchDialogHide() } .create() } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt index b0b9263034..2ed9fe33e0 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt @@ -58,6 +58,10 @@ sealed class TransactionExtrasAction : SendScreenActionUi { data class HandleUserInput(val data: String) : XlmMemo() } + sealed class BinanceMemo : TransactionExtrasAction() { + data class HandleUserInput(val data: String) : BinanceMemo() + } + sealed class XrpDestinationTag : TransactionExtrasAction() { data class HandleUserInput(val data: String) : XrpDestinationTag() } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt index 6ecd4514d4..4215143301 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt @@ -14,7 +14,8 @@ class TransactionExtrasReducer : SendInternalReducer { return when (action) { is Prepare -> handleInitialization(action, sendState) Release -> handleRelease(action, sendState) - is XlmMemo -> handleMemo(action, sendState, sendState.transactionExtrasState) + is XlmMemo -> handleXlmMemo(action, sendState, sendState.transactionExtrasState) + is BinanceMemo -> handleBinanceMemo(action, sendState, sendState.transactionExtrasState) is XrpDestinationTag -> handleXrpTag(action, sendState, sendState.transactionExtrasState) else -> sendState } @@ -40,6 +41,7 @@ class TransactionExtrasReducer : SendInternalReducer { } } Blockchain.Stellar -> TransactionExtrasState(xlmMemo = XlmMemoState()) + Blockchain.Binance -> TransactionExtrasState(binanceMemo = BinanceMemoState()) else -> emptyResult } return updateLastState(sendState.copy(transactionExtrasState = result), result) @@ -50,7 +52,7 @@ class TransactionExtrasReducer : SendInternalReducer { return updateLastState(sendState.copy(transactionExtrasState = result), result) } - private fun handleMemo( + private fun handleXlmMemo( action: XlmMemo, sendState: SendState, infoState: TransactionExtrasState, @@ -94,6 +96,26 @@ class TransactionExtrasReducer : SendInternalReducer { return updateLastState(sendState.copy(transactionExtrasState = result), result) } + private fun handleBinanceMemo( + action: BinanceMemo, + sendState: SendState, + infoState: TransactionExtrasState, + ): SendState { + val result = when (action) { + is BinanceMemo.HandleUserInput -> { + val tag = action.data.toBigIntegerOrNull() + if (tag != null) { + val input = InputViewValue(action.data, true) + val tagState = BinanceMemoState(input, tag) + infoState.copy(binanceMemo = tagState) + } else { + infoState + } + } + } + return updateLastState(sendState.copy(transactionExtrasState = result), result) + } + private fun handleXrpTag( action: XrpDestinationTag, sendState: SendState, diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index 4f2e4e1a6d..e4f816c106 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -27,6 +27,7 @@ data class AddressPayIdState( data class TransactionExtrasState( val xlmMemo: XlmMemoState? = null, + val binanceMemo: BinanceMemoState? = null, val xrpDestinationTag: XrpDestinationTagState? = null ) : IdStateHolder { override val stateId: StateId = StateId.TRANSACTION_EXTRAS @@ -54,6 +55,16 @@ data class XlmMemoState( } } +data class BinanceMemoState( + val viewFieldValue: InputViewValue = InputViewValue(""), + val memo: BigInteger? = null, + val error: TransactionExtraError? = null + ) { + companion object { + val MAX_NUMBER: BigInteger = BigInteger("FFFFFFFFFFFFFFFF", 16) + } +} + // tag must contains only digits data class XrpDestinationTagState( val viewFieldValue: InputViewValue = InputViewValue(""), @@ -67,5 +78,6 @@ data class XrpDestinationTagState( enum class TransactionExtraError { INVALID_DESTINATION_TAG, - INVALID_XLM_MEMO + INVALID_XLM_MEMO, + INVALID_BINANCE_MEMO } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index 4d9528605a..1f91fb98cb 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -115,7 +115,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { } private fun setupTransactionExtrasLayout() { - etMemo.inputtedTextAsFlow() + etXlmMemo.inputtedTextAsFlow() .debounce(400) .filter { val info = store.state.sendState.transactionExtrasState @@ -132,6 +132,15 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { } .onEach { store.dispatch(TransactionExtrasAction.XrpDestinationTag.HandleUserInput(it)) } .launchIn(mainScope) + + etBinanceMemo.inputtedTextAsFlow() + .debounce(400) + .filter { + val info = store.state.sendState.transactionExtrasState + info.binanceMemo?.viewFieldValue?.value != it + } + .onEach { store.dispatch(TransactionExtrasAction.BinanceMemo.HandleUserInput(it)) } + .launchIn(mainScope) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index a8987dcd0e..b90c53e080 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -7,6 +7,7 @@ import android.text.SpannableStringBuilder import android.view.View import android.view.ViewGroup import androidx.core.text.bold +import com.tangem.common.extensions.remove import com.tangem.tap.common.extensions.* import com.tangem.tap.common.redux.getMessageString import com.tangem.tap.common.text.DecimalDigitsInputFilter @@ -64,19 +65,20 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } showView(fg.xlmMemoContainer, infoState.xlmMemo) showView(fg.xrpDestinationTagContainer, infoState.xrpDestinationTag) + showView(fg.binanceMemoContainer, infoState.binanceMemo) infoState.xlmMemo?.let { - fg.etMemo.inputType = when (it.selectedMemoType) { + fg.etXlmMemo.inputType = when (it.selectedMemoType) { XlmMemoType.TEXT -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS XlmMemoType.ID -> InputType.TYPE_CLASS_NUMBER } - if (!it.viewFieldValue.isFromUserInput) fg.etMemo.setText(it.viewFieldValue.value) + if (!it.viewFieldValue.isFromUserInput) fg.etXlmMemo.setText(it.viewFieldValue.value) if (it.error != null) { if (it.error == TransactionExtraError.INVALID_XLM_MEMO) { - fg.tilMemo.error = fg.getText(R.string.send_error_invalid_memo_id) + fg.tilXlmMemo.error = fg.getText(R.string.send_error_invalid_memo_id) } } else { - fg.tilMemo.error = null + fg.tilXlmMemo.error = null } } infoState.xrpDestinationTag?.let { @@ -91,6 +93,18 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber fg.etDestinationTag.setText(it.viewFieldValue.value) } } + infoState.binanceMemo?.let { + if (infoState.binanceMemo.error != null) { + if (infoState.binanceMemo.error == TransactionExtraError.INVALID_BINANCE_MEMO) { + fg.tilBinanceMemo.error = fg.getText(R.string.send_error_invalid_memo_id) + } + } else { + fg.tilBinanceMemo.error = null + } + if (!it.viewFieldValue.isFromUserInput) { + fg.etBinanceMemo.setText(it.viewFieldValue.value) + } + } } private fun handleSendScreen(fg: BaseStoreFragment, state: SendState) { @@ -187,9 +201,13 @@ 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_subtitle_format, - state.mainCurrency.currencySymbol, - state.viewBalanceValue) + val balanceText = when (state.mainCurrency.type) { + MainCurrencyType.FIAT -> fg.getString(R.string.send_balance_subtitle_format, + state.viewBalanceValue, state.mainCurrency.currencySymbol).remove(":") + MainCurrencyType.CRYPTO -> fg.getString(R.string.send_balance_subtitle_format, + state.mainCurrency.currencySymbol, state.viewBalanceValue) + } + fg.tvBalance.update(balanceText) fg.tilAmountToSend.isEnabled = state.inputIsEnabled diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/CurrencyListItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/CurrencyListItem.kt new file mode 100644 index 0000000000..98efd84540 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/CurrencyListItem.kt @@ -0,0 +1,66 @@ +package com.tangem.tap.features.tokens.redux + +import androidx.annotation.StringRes +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.wallet.R + +sealed class CurrencyListItem { + data class TokenListItem(val token: Token) : CurrencyListItem() + data class BlockchainListItem(val blockchain: Blockchain) : CurrencyListItem() + data class TitleListItem( + @StringRes val titleResId: Int, + var isContentShown: Boolean = true, + val blockchain: Blockchain? = null, + ) : CurrencyListItem() + + companion object { + fun createListOfCurrencies( + blockchains: List, + tokens: List, + ): List { + val blockchainsTitle = R.string.add_tokens_subtitle_blockchains + val ethereumTokensTitle = R.string.add_tokens_subtitle_ethereum_tokens + val bscTokensTitle = R.string.add_tokens_subtitle_bsc_tokens + val binanceTokensTitle = R.string.add_tokens_subtitle_binance_tokens + + val ethereumTokens = tokens.filter { it.blockchain == Blockchain.Ethereum } + val bscTokens = tokens.filter { it.blockchain == Blockchain.BSC } + val binanceTokens = tokens.filter { it.blockchain == Blockchain.Binance } + return listOf(TitleListItem(blockchainsTitle)) + + blockchains.map { BlockchainListItem(it) } + + listOf(TitleListItem(ethereumTokensTitle, blockchain = Blockchain.Ethereum)) + + ethereumTokens.map { TokenListItem(it) } + + listOf(TitleListItem(bscTokensTitle, blockchain = Blockchain.BSC)) + + bscTokens.map { TokenListItem(it) } + + listOf(TitleListItem(binanceTokensTitle, blockchain = Blockchain.Binance)) + + binanceTokens.map { TokenListItem(it) } + } + } +} + +fun List.removeTokensForBlockchain(blockchain: Blockchain): List { + return filterNot { + it is CurrencyListItem.TokenListItem && it.token.blockchain == blockchain + } +} + +fun List.addTokensForBlockchain( + blockchain: Blockchain, fullCurrenciesList: List, +): List { + val tokensToAdd = fullCurrenciesList.filter { + it is CurrencyListItem.TokenListItem && it.token.blockchain == blockchain + } + val indexToInsert = indexOfFirst { + it is CurrencyListItem.TitleListItem && it.blockchain == blockchain + } + 1 + return this.toMutableList().apply { addAll(indexToInsert, tokensToAdd) } +} + +fun List.toggleHeaderContentShownValue(blockchain: Blockchain) { + map { + if (it is CurrencyListItem.TitleListItem && it.blockchain == blockchain) { + it.isContentShown = !it.isContentShown + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt index e0c9abe119..1be9e7c701 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensAction.kt @@ -1,7 +1,7 @@ package com.tangem.tap.features.tokens.redux +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token -import com.tangem.tap.features.tokens.ui.adapters.CurrencyListItem import com.tangem.tap.features.wallet.redux.WalletData import org.rekotlin.Action @@ -17,5 +17,6 @@ sealed class TokensAction : Action { data class SetAddedCurrencies(val wallets: List) : TokensAction() + data class ToggleShowTokensForBlockchain(val isShown: Boolean, val blockchain: Blockchain) : TokensAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index e8afbe2d62..6ecff3f595 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -3,7 +3,6 @@ package com.tangem.tap.features.tokens.redux import com.tangem.tap.common.redux.AppState import com.tangem.tap.currenciesRepository import com.tangem.tap.domain.TapWorkarounds.isTestCard -import com.tangem.tap.features.tokens.ui.adapters.CurrencyListItem import com.tangem.tap.store import org.rekotlin.Middleware diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt index 878eed1113..f221424d67 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensReducer.kt @@ -18,7 +18,7 @@ private fun internalReduce(action: Action, state: AppState): TokensState { val tokensState = state.tokensState return when (action) { is TokensAction.LoadCurrencies.Success -> { - tokensState.copy(currencies = action.currencies) + tokensState.copy(currencies = action.currencies, shownCurrencies = action.currencies) } is TokensAction.SetAddedCurrencies -> { tokensState.copy(addedCurrencies = action.wallets.toCardCurrencies()) @@ -28,6 +28,20 @@ private fun internalReduce(action: Action, state: AppState): TokensState { action.tokens.map { TokenWithAmount(it, null) } )) } + + is TokensAction.ToggleShowTokensForBlockchain -> { + if (action.isShown) { + val shownCurrencies = tokensState.shownCurrencies + .removeTokensForBlockchain(action.blockchain) + shownCurrencies.toggleHeaderContentShownValue(action.blockchain) + tokensState.copy(shownCurrencies = shownCurrencies) + } else { + val shownCurrencies = tokensState.shownCurrencies + .addTokensForBlockchain(action.blockchain, tokensState.currencies) + shownCurrencies.toggleHeaderContentShownValue(action.blockchain) + tokensState.copy(shownCurrencies = shownCurrencies) + } + } else -> tokensState } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt index b3d528fe5f..ef30a92229 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensState.kt @@ -2,15 +2,14 @@ package com.tangem.tap.features.tokens.redux import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.Token -import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.domain.tokens.CardCurrencies -import com.tangem.tap.features.tokens.ui.adapters.CurrencyListItem import org.rekotlin.StateType data class TokensState( val addedTokens: LinkedHashSet = LinkedHashSet(), val addedCurrencies: CardCurrencies? = null, val currencies: List = emptyList(), + val shownCurrencies: List = emptyList(), ) : StateType data class TokenWithAmount( diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt index 4b88b06ca5..b5d09b7074 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt @@ -73,7 +73,7 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), override fun newState(state: TokensState) { if (activity == null) return viewAdapter.addedCurrencies = state.addedCurrencies - viewAdapter.submitUnfilteredList(state.currencies) + viewAdapter.submitUnfilteredList(state.shownCurrencies) } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/adapters/CurrenciesAdapter.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/adapters/CurrenciesAdapter.kt index 918dd2916a..85a8462b81 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/adapters/CurrenciesAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/adapters/CurrenciesAdapter.kt @@ -3,18 +3,17 @@ package com.tangem.tap.features.tokens.ui.adapters import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.annotation.StringRes import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.squareup.picasso.Picasso -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token import com.tangem.tap.common.extensions.getString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.loadCurrenciesIcon import com.tangem.tap.common.extensions.show import com.tangem.tap.domain.tokens.CardCurrencies +import com.tangem.tap.features.tokens.redux.CurrencyListItem +import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.store import com.tangem.wallet.R @@ -68,11 +67,11 @@ class CurrenciesAdapter : ListAdapter object DiffUtilCallback : DiffUtil.ItemCallback() { override fun areContentsTheSame( - oldItem: CurrencyListItem, newItem: CurrencyListItem + oldItem: CurrencyListItem, newItem: CurrencyListItem, ) = oldItem == newItem override fun areItemsTheSame( - oldItem: CurrencyListItem, newItem: CurrencyListItem + oldItem: CurrencyListItem, newItem: CurrencyListItem, ) = oldItem == newItem } @@ -161,38 +160,21 @@ class CurrenciesAdapter : ListAdapter class TitleViewHolder(val view: View) : RecyclerView.ViewHolder(view) { fun bind(title: CurrencyListItem.TitleListItem) { - view.tv_subtitle.text = view.getString(title.titleResId).toUpperCase(Locale.US) - } - } -} - - -sealed class CurrencyListItem { - data class TokenListItem(val token: Token) : CurrencyListItem() - data class BlockchainListItem(val blockchain: Blockchain) : CurrencyListItem() - data class TitleListItem(@StringRes val titleResId: Int) : CurrencyListItem() - - companion object { - fun createListOfCurrencies( - blockchains: List, - tokens: List - ): List { - val blockchainsTitle = R.string.add_tokens_subtitle_blockchains - val ethereumTokensTitle = R.string.add_tokens_subtitle_ethereum_tokens - val bscTokensTitle = R.string.add_tokens_subtitle_bsc_tokens - val binanceTokensTitle = R.string.add_tokens_subtitle_binance_tokens - - val ethereumTokens = tokens.filter { it.blockchain == Blockchain.Ethereum } - val bscTokens = tokens.filter { it.blockchain == Blockchain.BSC } - val binanceTokens = tokens.filter { it.blockchain == Blockchain.Binance } - return listOf(TitleListItem(blockchainsTitle)) + - blockchains.map { BlockchainListItem(it) } + - listOf(TitleListItem(ethereumTokensTitle)) + - ethereumTokens.map { TokenListItem(it) } + - listOf(TitleListItem(bscTokensTitle)) + - bscTokens.map { TokenListItem(it) } + - listOf(TitleListItem(binanceTokensTitle)) + - binanceTokens.map { TokenListItem(it) } + view.tv_subtitle.text = view.getString(title.titleResId).uppercase() + + if (title.blockchain != null) { + view.cl_subtitle_container.setOnClickListener { + val rotation = if (title.isContentShown) -90f else 0f + store.dispatch(TokensAction.ToggleShowTokensForBlockchain( + title.isContentShown, title.blockchain + )) + view.iv_toggle_sublist_visibility.animate().rotation(rotation) + } + view.iv_toggle_sublist_visibility.show() + view.iv_toggle_sublist_visibility.setImageResource(R.drawable.ic_arrow_angle_down) + } else { + view.iv_toggle_sublist_visibility.hide() + } } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 154f46bd8a..41a3dc9258 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -145,7 +145,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS Picasso.get().loadCurrenciesIcon( imageView = iv_currency, textView = tv_token_letter, - blockchain = wallet.currency?.blockchain, + blockchain = wallet.currency.blockchain, token = (wallet.currency as? Currency.Token)?.token ) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt index f804f6acef..4d96d05004 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt @@ -63,7 +63,7 @@ class WalletAdapter view.card_wallet.setOnClickListener { store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet)) } - val blockchain = wallet.currency?.blockchain + val blockchain = wallet.currency.blockchain val token = (wallet.currency as? Currency.Token)?.token Picasso.get().loadCurrenciesIcon( diff --git a/app/src/main/res/drawable/ic_arrow_angle_down.xml b/app/src/main/res/drawable/ic_arrow_angle_down.xml new file mode 100644 index 0000000000..e773e9862f --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_angle_down.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_angle_right.xml b/app/src/main/res/drawable/ic_arrow_angle_right.xml new file mode 100644 index 0000000000..c009fd11a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_angle_right.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/item_currency_subtitle.xml b/app/src/main/res/layout/item_currency_subtitle.xml index c4ae27800d..677c928c32 100644 --- a/app/src/main/res/layout/item_currency_subtitle.xml +++ b/app/src/main/res/layout/item_currency_subtitle.xml @@ -2,6 +2,7 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_currency_wallet.xml b/app/src/main/res/layout/item_currency_wallet.xml index 3b74abdffd..05af6fcb26 100644 --- a/app/src/main/res/layout/item_currency_wallet.xml +++ b/app/src/main/res/layout/item_currency_wallet.xml @@ -52,33 +52,56 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_percent="0.5"/> + app:layout_constraintGuide_percent="0.5" /> + app:layout_constraintEnd_toStartOf="@+id/tv_amount" + app:layout_constraintStart_toEndOf="@id/iv_currency" + app:layout_constraintTop_toTopOf="parent" + tools:text="Binance Smart Chain Optimal" /> + app:layout_constraintGuide_percent="0.45" + app:layout_constraintTop_toTopOf="parent" /> + + + app:layout_constraintStart_toEndOf="@id/iv_currency" + app:layout_constraintTop_toTopOf="@id/guideline" /> - - @@ -168,8 +171,8 @@ android:textColor="@color/darkGray2" android:textSize="14sp" app:layout_constraintBottom_toBottomOf="@id/tv_exchange_rate" - app:layout_constraintTop_toTopOf="@id/tv_exchange_rate" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="@id/tv_exchange_rate" tools:text="0.43 USD" /> diff --git a/app/src/main/res/layout/item_popular_token.xml b/app/src/main/res/layout/item_popular_token.xml index a052651d61..976047b14b 100644 --- a/app/src/main/res/layout/item_popular_token.xml +++ b/app/src/main/res/layout/item_popular_token.xml @@ -4,9 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="52dp" android:layout_marginBottom="1dp" - android:background="@android:color/white"> + android:background="@android:color/white" + android:minHeight="60dp"> + app:layout_constraintGuide_percent="0.5" /> + tools:text="Binance Smart Chain Optimal" /> + + + app:layout_constraintHorizontal_bias="1.0" + app:layout_constraintStart_toStartOf="@+id/guideline2" + tools:text="111230.98123128293475943 BTC" /> + tools:text="0.00434143 ETH" /> + android:gravity="end" + android:textColor="@color/darkGray1" + tools:text="123.29837729 ADA 39487593.109342039402938049 will be sent" /> diff --git a/app/src/main/res/layout/layout_send_address_payid.xml b/app/src/main/res/layout/layout_send_address_payid.xml index 2b0f046335..232b778f22 100644 --- a/app/src/main/res/layout/layout_send_address_payid.xml +++ b/app/src/main/res/layout/layout_send_address_payid.xml @@ -140,7 +140,7 @@ + + + + + + + + + + The wallet creation procedure consists of three steps. You must complete it to the end, otherwise you will have to start from the beginning. Tap the card #%s You have already started the process of recreating twin wallet. If you interrupt it, you won\'t be able to use your twin cards until you start it again and complete recreating the wallet. + You\'ve tapped the same card. To create twin wallet you need to tap a second twin card. The twin address was successfully created @@ -90,6 +91,7 @@ ex. USDC Added Remove token + Token icon //Details Blockchain @@ -198,10 +200,12 @@ Send only %s (%s) from %s network to this address. Sending any other currency will result in its irreversible loss. If the process of re-creating the wallet gets interrupted in any way, you’ll have to start over. + The twinning process is partly complete. You can’t exit it now. Internal error: can\'t create wallet manager Blockchain is unreachable. Try later + Ok, Got it!