From 90b49e37739ff8785732995aece530a3e5be31e1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 14 Jun 2023 13:15:01 +0800 Subject: [PATCH 01/27] Updated on 2026-08-14 --- gradle/dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index ab2fb12799..49c4ee774b 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -77,9 +77,9 @@ walletConnectWeb3 = "1.8.0" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-240" +tangemBlockchainSdk = "release-app_4.7-241" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-266" +tangemCardSdk = "release-app_4.7-268" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds # endregion Tangem From 74dea8f85ba19b2e2319d78f6df752a4692c340c Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 14 Jun 2023 18:28:02 +0400 Subject: [PATCH 02/27] Updated on 2026-08-14 --- .../presentation/viewmodels/AddCustomTokenViewModel.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt index 1d886914c7..5ccb8e66e6 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt @@ -510,7 +510,7 @@ internal class AddCustomTokenViewModel @Inject constructor( val sameAddress = contractAddress == wrappedCurrency.token.contractAddress val sameBlockchain = Blockchain.fromNetworkId(networkSelectorValue.toNetworkId()) == wrappedCurrency.blockchain - val isSameDerivationPath = getDerivationPath()?.rawPath == wrappedCurrency.derivationPath + val isSameDerivationPath = getDerivationPath().isSameDerivationPath(wrappedCurrency.derivationPath) sameId && sameAddress && sameBlockchain && isSameDerivationPath } } @@ -522,10 +522,15 @@ internal class AddCustomTokenViewModel @Inject constructor( .filterIsInstance() .any { val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain - networkSelectorValue == it.blockchain && getDerivationPath()?.rawPath == it.derivationPath + networkSelectorValue == it.blockchain && + getDerivationPath().isSameDerivationPath(it.derivationPath) } } + private fun DerivationPath?.isSameDerivationPath(rawDerivationPath: String?): Boolean { + return this == rawDerivationPath?.let { DerivationPath(it) } + } + private fun handleContractAddressErrorValidation(type: AddCustomTokenError) { when { isNetworkSelected() && type == AddCustomTokenError.InvalidContractAddress -> { From f49f61ace0e9dc331fbb4c9ba694da8070791b51 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 15 Jun 2023 14:13:56 +0300 Subject: [PATCH 03/27] Updated on 2026-08-14 --- app/src/main/AndroidManifest.xml | 1 + app/src/main/res/values-v24/bool.xml | 5 +++++ app/src/main/res/values/bool.xml | 5 +++++ 3 files changed, 11 insertions(+) create mode 100644 app/src/main/res/values-v24/bool.xml create mode 100644 app/src/main/res/values/bool.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a9226c6eff..2bb55e36b4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,6 +37,7 @@ android:fullBackupContent="false" android:networkSecurityConfig="@xml/network_security_config" android:hardwareAccelerated="true" + android:largeHeap="@bool/largeHeap" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:allowBackup, android:fullBackupContent"> diff --git a/app/src/main/res/values-v24/bool.xml b/app/src/main/res/values-v24/bool.xml new file mode 100644 index 0000000000..093ecf3bc6 --- /dev/null +++ b/app/src/main/res/values-v24/bool.xml @@ -0,0 +1,5 @@ + + + false + + diff --git a/app/src/main/res/values/bool.xml b/app/src/main/res/values/bool.xml new file mode 100644 index 0000000000..d5677354f0 --- /dev/null +++ b/app/src/main/res/values/bool.xml @@ -0,0 +1,5 @@ + + + true + + From 8cfc4bfe051d6266ebdd2ad6a7460723f74df2b6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 18:55:28 +0300 Subject: [PATCH 04/27] Updated on 2026-08-14 --- .gitignore | 1 + app/src/main/AndroidManifest.xml | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 25c98d5d1f..3e96fb9767 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # Built application files /build +/buildSrc # Local configuration file (sdk path, etc) local.properties diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2bb55e36b4..ef93ea2179 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,17 +27,16 @@ @@ -46,10 +45,11 @@ android:value="true" /> @@ -126,13 +126,17 @@ - + - + Date: Fri, 16 Jun 2023 23:56:26 +0800 Subject: [PATCH 05/27] Updated on 2026-08-14 --- .../tap/features/send/ui/EditTextCustomPaste.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/EditTextCustomPaste.kt b/app/src/main/java/com/tangem/tap/features/send/ui/EditTextCustomPaste.kt index d3b563025d..d93147b24b 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/EditTextCustomPaste.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/EditTextCustomPaste.kt @@ -5,14 +5,16 @@ import android.content.Context import android.util.AttributeSet import com.google.android.material.textfield.TextInputEditText -class EditTextCustomPaste @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0, -) : TextInputEditText(context, attrs, defStyleAttr) { +class EditTextCustomPaste : TextInputEditText { private var onSystemPasteButtonClickListener: (() -> Unit)? = null + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + fun setOnSystemPasteButtonClickListener(callback: () -> Unit) { onSystemPasteButtonClickListener = callback } From 16f8451745083c4aac6a1396619e7fcac36bcf30 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 23:57:48 +0800 Subject: [PATCH 06/27] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 49c4ee774b..4b14f8518a 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -77,7 +77,7 @@ walletConnectWeb3 = "1.8.0" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_4.7-241" +tangemBlockchainSdk = "release-app_4.7-243" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_4.7-268" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds From 00de15f8e0b09a1b65f77b331b4813d90ee521e4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 16:36:56 +0800 Subject: [PATCH 07/27] Updated on 2026-08-14 --- .../shop/data/DefaultShopRepository.kt | 37 ++++++++++ .../tap/features/shop/di/ShopUseCaseModule.kt | 28 ++++++++ ...faultShopifyOrderingAvailabilityUseCase.kt | 15 ++++ .../features/shop/domain/ShopRepository.kt | 12 ++++ .../ShopifyOrderingAvailabilityUseCase.kt | 12 ++++ .../shop/presentation/ShopViewModel.kt | 39 ++++++++++ .../tap/features/shop/redux/ShopAction.kt | 40 ++++++----- .../tap/features/shop/redux/ShopReducer.kt | 71 ++++++------------- .../tap/features/shop/redux/ShopState.kt | 1 + .../tap/features/shop/ui/ShopFragment.kt | 16 ++++- app/src/main/res/layout/fragment_shop.xml | 2 +- .../api/tangemTech/TangemTechApi.kt | 3 + .../api/tangemTech/models/ShopResponse.kt | 14 ++++ core/res/src/main/res/values-ru/strings.xml | 2 +- core/res/src/main/res/values/strings.xml | 2 +- 15 files changed, 223 insertions(+), 71 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt create mode 100644 app/src/main/java/com/tangem/tap/features/shop/di/ShopUseCaseModule.kt create mode 100644 app/src/main/java/com/tangem/tap/features/shop/domain/DefaultShopifyOrderingAvailabilityUseCase.kt create mode 100644 app/src/main/java/com/tangem/tap/features/shop/domain/ShopRepository.kt create mode 100644 app/src/main/java/com/tangem/tap/features/shop/domain/ShopifyOrderingAvailabilityUseCase.kt create mode 100644 app/src/main/java/com/tangem/tap/features/shop/presentation/ShopViewModel.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/ShopResponse.kt diff --git a/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt b/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt new file mode 100644 index 0000000000..8f61a43c5f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.features.shop.data + +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.api.tangemTech.models.ShopResponse +import com.tangem.tap.features.shop.domain.ShopRepository +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching +import timber.log.Timber + +/** + * Default implementation of shop feature repository + * + * @property tangemTechApi TangemTech API + * @property dispatchers coroutine dispatchers provider + * +[REDACTED_AUTHOR] + */ +internal class DefaultShopRepository( + private val tangemTechApi: TangemTechApi, + private val dispatchers: CoroutineDispatcherProvider, +) : ShopRepository { + + override suspend fun isShopifyOrderingAvailable(): Boolean { + return runCatching(dispatchers.io) { tangemTechApi.getShopInfo(name = SHOPIFY_NAME) } + .fold( + onSuccess = ShopResponse::isOrderingAvailable, + onFailure = { + Timber.e("Server error. isShopifyOrderingAvailable returns default value (false)") + false + }, + ) + } + + private companion object { + const val SHOPIFY_NAME = "shopify" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/di/ShopUseCaseModule.kt b/app/src/main/java/com/tangem/tap/features/shop/di/ShopUseCaseModule.kt new file mode 100644 index 0000000000..2c00aa1181 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/shop/di/ShopUseCaseModule.kt @@ -0,0 +1,28 @@ +package com.tangem.tap.features.shop.di + +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.tap.features.shop.data.DefaultShopRepository +import com.tangem.tap.features.shop.domain.DefaultShopifyOrderingAvailabilityUseCase +import com.tangem.tap.features.shop.domain.ShopifyOrderingAvailabilityUseCase +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.scopes.ViewModelScoped + +@Module +@InstallIn(ViewModelComponent::class) +internal object ShopUseCaseModule { + + @Provides + @ViewModelScoped + fun provideShopifyOrderingAvailabilityUseCase( + tangemTechApi: TangemTechApi, + dispatchers: CoroutineDispatcherProvider, + ): ShopifyOrderingAvailabilityUseCase { + return DefaultShopifyOrderingAvailabilityUseCase( + shopRepository = DefaultShopRepository(tangemTechApi, dispatchers), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/domain/DefaultShopifyOrderingAvailabilityUseCase.kt b/app/src/main/java/com/tangem/tap/features/shop/domain/DefaultShopifyOrderingAvailabilityUseCase.kt new file mode 100644 index 0000000000..41bbe3d449 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/shop/domain/DefaultShopifyOrderingAvailabilityUseCase.kt @@ -0,0 +1,15 @@ +package com.tangem.tap.features.shop.domain + +/** + * Default implementation of use case to define shopify ordering availability + * + * @property shopRepository shop feature repository + * +[REDACTED_AUTHOR] + */ +internal class DefaultShopifyOrderingAvailabilityUseCase( + private val shopRepository: ShopRepository, +) : ShopifyOrderingAvailabilityUseCase { + + override suspend fun invoke() = shopRepository.isShopifyOrderingAvailable() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/domain/ShopRepository.kt b/app/src/main/java/com/tangem/tap/features/shop/domain/ShopRepository.kt new file mode 100644 index 0000000000..c8cd6f3780 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/shop/domain/ShopRepository.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.features.shop.domain + +/** + * Shop feature repository + * +[REDACTED_AUTHOR] + */ +internal interface ShopRepository { + + /** Get shopify ordering availability */ + suspend fun isShopifyOrderingAvailable(): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/domain/ShopifyOrderingAvailabilityUseCase.kt b/app/src/main/java/com/tangem/tap/features/shop/domain/ShopifyOrderingAvailabilityUseCase.kt new file mode 100644 index 0000000000..5f6c351ce2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/shop/domain/ShopifyOrderingAvailabilityUseCase.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.features.shop.domain + +/** + * Use case to define shopify ordering availability + * +[REDACTED_AUTHOR] + */ +internal interface ShopifyOrderingAvailabilityUseCase { + + /** Get availability */ + suspend operator fun invoke(): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/presentation/ShopViewModel.kt b/app/src/main/java/com/tangem/tap/features/shop/presentation/ShopViewModel.kt new file mode 100644 index 0000000000..34966466cc --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/shop/presentation/ShopViewModel.kt @@ -0,0 +1,39 @@ +package com.tangem.tap.features.shop.presentation + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.tangem.tap.features.shop.domain.ShopifyOrderingAvailabilityUseCase +import com.tangem.tap.features.shop.redux.ShopAction +import com.tangem.tap.proxy.AppStateHolder +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +/** + * Shop screen view model + * + * @property shopifyOrderingAvailabilityUseCase use case to define shopify ordering availability + * @property dispatchers coroutine dispatchers provider + * @property appStateHolder redux state holder + * +[REDACTED_AUTHOR] + */ +@HiltViewModel +internal class ShopViewModel @Inject constructor( + private val shopifyOrderingAvailabilityUseCase: ShopifyOrderingAvailabilityUseCase, + private val dispatchers: CoroutineDispatcherProvider, + private val appStateHolder: AppStateHolder, +) : ViewModel() { + + /** Check ordering delay block visibility */ + fun checkOrderingDelayBlockVisibility() { + viewModelScope.launch(dispatchers.main) { + val visibility = runCatching(dispatchers.io) { shopifyOrderingAvailabilityUseCase() } + .fold(onSuccess = { !it }, onFailure = { false }) + + appStateHolder.mainStore?.dispatch(action = ShopAction.SetOrderingDelayBlockVisibility(visibility)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt index 219753c469..54c6bcad43 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopAction.kt @@ -8,38 +8,40 @@ import com.tangem.tap.common.shop.googlepay.GooglePayService import com.tangem.wallet.R import org.rekotlin.Action -sealed class ShopAction : Action { +sealed interface ShopAction : Action { - object LoadProducts : ShopAction() { - data class Success(val products: List) : ShopAction() - object Failure : ShopAction(), NotificationAction { + object LoadProducts : ShopAction { + data class Success(val products: List) : ShopAction + object Failure : ShopAction, NotificationAction { override val messageResource = R.string.common_server_unavailable } } - data class ApplyPromoCode(val promoCode: String) : ShopAction() { - data class Success(val promoCode: String?, val products: List) : ShopAction() - object InvalidPromoCode : ShopAction() + data class ApplyPromoCode(val promoCode: String) : ShopAction { + data class Success(val promoCode: String?, val products: List) : ShopAction + object InvalidPromoCode : ShopAction } - object BuyWithGooglePay : ShopAction() { - object UserCancelled : ShopAction() - data class HandleGooglePayResponse(val resultCode: Int, val data: Intent?) : ShopAction() + object BuyWithGooglePay : ShopAction { + object UserCancelled : ShopAction + data class HandleGooglePayResponse(val resultCode: Int, val data: Intent?) : ShopAction - data class Failure(val exception: Throwable) : ShopAction() - object Success : ShopAction() + data class Failure(val exception: Throwable) : ShopAction + object Success : ShopAction } - object StartWebCheckout : ShopAction() + object StartWebCheckout : ShopAction - data class CheckIfGooglePayAvailable(val googlePayService: GooglePayService) : ShopAction() { - object Success : ShopAction() - object Failure : ShopAction() + data class CheckIfGooglePayAvailable(val googlePayService: GooglePayService) : ShopAction { + object Success : ShopAction + object Failure : ShopAction } - data class SelectProduct(val productType: ProductType) : ShopAction() + data class SelectProduct(val productType: ProductType) : ShopAction - object FinishSuccessfulOrder : ShopAction() + object FinishSuccessfulOrder : ShopAction - object ResetState : ShopAction() + object ResetState : ShopAction + + data class SetOrderingDelayBlockVisibility(val visibility: Boolean) : ShopAction } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt index 8a97a1a58c..60cb0667ad 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopReducer.kt @@ -6,63 +6,38 @@ object ShopReducer { fun reduce(action: Action, state: ShopState): ShopState = internalReduce(action, state) } -@Suppress("ComplexMethod") private fun internalReduce(action: Action, state: ShopState): ShopState { if (action !is ShopAction) return state return when (action) { - is ShopAction.ApplyPromoCode -> state.copy( - promoCode = action.promoCode, - promoCodeLoading = true, - ) - ShopAction.BuyWithGooglePay -> state - ShopAction.LoadProducts -> state - is ShopAction.LoadProducts.Success -> { - state.copy( - availableProducts = action.products, - ) - } - ShopAction.StartWebCheckout -> state - ShopAction.ApplyPromoCode.InvalidPromoCode -> state.copy( - promoCode = null, - promoCodeLoading = false, - ) + is ShopAction.ApplyPromoCode -> state.copy(promoCode = action.promoCode, promoCodeLoading = true) + is ShopAction.LoadProducts.Success -> state.copy(availableProducts = action.products) + is ShopAction.ApplyPromoCode.InvalidPromoCode -> state.copy(promoCode = null, promoCodeLoading = false) is ShopAction.ApplyPromoCode.Success -> { state.copy( promoCode = action.promoCode, availableProducts = action.products, promoCodeLoading = false, + ) + } + is ShopAction.SelectProduct -> state.copy(selectedProduct = action.productType) - ) - } - is ShopAction.SelectProduct -> { - state.copy( - selectedProduct = action.productType, - ) - } - is ShopAction.CheckIfGooglePayAvailable -> { - state - } - ShopAction.CheckIfGooglePayAvailable.Failure -> { - state.copy(isGooglePayAvailable = false) - } - ShopAction.CheckIfGooglePayAvailable.Success -> { - state.copy(isGooglePayAvailable = false) // TODO: change when we add support for GPay - } - is ShopAction.BuyWithGooglePay.Failure -> { - state - } - is ShopAction.BuyWithGooglePay.HandleGooglePayResponse -> { - state - } - ShopAction.BuyWithGooglePay.Success -> { - state - } - ShopAction.BuyWithGooglePay.UserCancelled -> { - state - } - ShopAction.FinishSuccessfulOrder -> state - ShopAction.ResetState -> ShopState() - ShopAction.LoadProducts.Failure -> state + // TODO: change when we add support for GPay + is ShopAction.CheckIfGooglePayAvailable.Failure -> state.copy(isGooglePayAvailable = false) + is ShopAction.CheckIfGooglePayAvailable.Success -> state.copy(isGooglePayAvailable = false) + + is ShopAction.ResetState -> ShopState() + is ShopAction.SetOrderingDelayBlockVisibility -> state.copy(isOrderingDelayBlockVisible = action.visibility) + is ShopAction.BuyWithGooglePay, + is ShopAction.LoadProducts, + is ShopAction.StartWebCheckout, + is ShopAction.CheckIfGooglePayAvailable, + is ShopAction.BuyWithGooglePay.Failure, + is ShopAction.BuyWithGooglePay.HandleGooglePayResponse, + is ShopAction.BuyWithGooglePay.Success, + is ShopAction.BuyWithGooglePay.UserCancelled, + is ShopAction.FinishSuccessfulOrder, + is ShopAction.LoadProducts.Failure, + -> state } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopState.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopState.kt index ebbbb7cb79..491e961e58 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopState.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopState.kt @@ -10,6 +10,7 @@ data class ShopState( val promoCode: String? = null, val promoCodeLoading: Boolean = false, val isGooglePayAvailable: Boolean = false, // TODO: change when we add support for GPay + val isOrderingDelayBlockVisible: Boolean = false, ) : StateType { val total: String? get() = availableProducts.firstOrNull { it.type == selectedProduct }?.totalSum?.finalValue diff --git a/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt b/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt index dccbe4d7b7..56ffe54b0f 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt @@ -9,28 +9,35 @@ import android.view.View.OnFocusChangeListener import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.viewModels import by.kirich1409.viewbindingdelegate.viewBinding import com.tangem.tap.common.GlobalLayoutStateHandler import com.tangem.tap.common.KeyboardObserver import com.tangem.tap.common.extensions.getQuantityString +import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.shop.data.ProductType import com.tangem.tap.features.BaseStoreFragment +import com.tangem.tap.features.shop.presentation.ShopViewModel import com.tangem.tap.features.shop.redux.ShopAction import com.tangem.tap.features.shop.redux.ShopState import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.FragmentShopBinding +import dagger.hilt.android.AndroidEntryPoint import org.rekotlin.StoreSubscriber -class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber { +@AndroidEntryPoint +internal class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber { private val binding: FragmentShopBinding by viewBinding(FragmentShopBinding::bind) private var cardTranslationY = 70f private lateinit var keyboardObserver: KeyboardObserver + private val viewModel by viewModels() + override fun subscribeToStore() { store.subscribe(this) { state -> state.skipRepeats { oldState, newState -> @@ -43,6 +50,8 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber< override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + viewModel.checkOrderingDelayBlockVisibility() + activity?.onBackPressedDispatcher?.addCallback( this, object : OnBackPressedCallback(true) { @@ -133,6 +142,7 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber< animateProductSelection(state.selectedProduct) handlePriceState(state) handlePromoCodeState(state) + handleOrderingDelayBlock(isVisible = state.isOrderingDelayBlockVisible) handleButtonsState(state) } @@ -173,6 +183,10 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber< pbPromoCode.show(state.promoCodeLoading) } + private fun handleOrderingDelayBlock(isVisible: Boolean) { + if (isVisible) binding.tvSoldOutDesc.show() else binding.tvSoldOutDesc.hide() + } + private fun handleButtonsState(state: ShopState) = with(binding) { btnPayGooglePay.root.show(state.isGooglePayAvailable) btnAlternativePayment.show(state.isGooglePayAvailable) diff --git a/app/src/main/res/layout/fragment_shop.xml b/app/src/main/res/layout/fragment_shop.xml index 523b68c535..0a61bf5b4a 100644 --- a/app/src/main/res/layout/fragment_shop.xml +++ b/app/src/main/res/layout/fragment_shop.xml @@ -271,7 +271,7 @@ android:layout_marginTop="14dp" android:background="@drawable/shape_rectangle_rounded_4" android:padding="16dp" - android:text="@string/shop_sold_out_description_prefix" + android:text="@string/shop_sold_out_description" android:textColor="@color/text_tertiary" android:textSize="16sp" /> diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 4125f7ed48..992f6d0eb5 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -51,4 +51,7 @@ interface TangemTechApi { @Header("card_id") cardId: String, @Body startReferralBody: StartReferralBody, ): ReferralResponse + + @GET("shops") + suspend fun getShopInfo(@Query(value = "name") name: String): ShopResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/ShopResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/ShopResponse.kt new file mode 100644 index 0000000000..6331011641 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/ShopResponse.kt @@ -0,0 +1,14 @@ +package com.tangem.datasource.api.tangemTech.models + +import com.squareup.moshi.Json + +/** + * Shop response + * + * @property isOrderingAvailable ordering availability + * +[REDACTED_AUTHOR] + */ +data class ShopResponse( + @Json(name = "canOrder") val isOrderingAvailable: Boolean, +) \ No newline at end of file diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 2baace2c4d..e994de868f 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -336,7 +336,7 @@ У меня есть промо-код… Tangem Wallet Другие способы оплаты - Из-за большого количества заказов, которые мы получаем, cроки доставки могут быть увеличены. + Из-за высокого количества заказов, которые мы получаем, доставка может быть задержана на срок до 5 недель в зависимости от вашего местоположения Итого Сеть Solana взимает арендную плату в размере %1$s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %2$s, чтобы не платить арендную плату. Держите свои криптосбережения в безопасности. Приватные ключи надежно хранятся на карте. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index ea3c2c3c93..11ef0d6d75 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -332,7 +332,7 @@ I have a promo code… Tangem Wallet Other payment methods - Due to the high volume of orders we are receiving, Shipping and Local Delivery orders may be delayed. + Due to the high volume of orders we are receiving shipping may be delayed up to 5 weeks depending on your location Total Solana network charges a rent of %1$s every 2 days. Accounts that can\'t afford the rent are purged from the network. Deposit your account with more than %2$s to use it for free. Store your crypto assets secure while keeping private keys contained in your card From 0fc9ce834b6724d210f06bff054f268c63771798 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 18:19:24 +0800 Subject: [PATCH 08/27] Updated on 2026-08-14 --- .../src/main/assets/configs/feature_toggles_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index 174175e4e6..b0b9550686 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -9,7 +9,7 @@ }, { "name": "NEW_CARD_SCANNING_ENABLED", - "version": "4.7.0" + "version": "4.8.0" }, { "name": "REDESIGNED_WALLET_SCREEN_ENABLED", From 9ad060cc85a636e2e01e4a4ef2afd85164cd2714 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 15:31:21 +0400 Subject: [PATCH 09/27] Updated on 2026-08-14 --- .../com/tangem/tap/common/DialogManager.kt | 11 +++++-- .../data/WalletConnectRepositoryImpl.kt | 27 ++++++++++------ .../domain/WalletConnectInteractor.kt | 32 +++++++++++-------- .../domain/models/WalletConnectError.kt | 2 +- .../walletconnect/WalletConnectMiddleware.kt | 15 +++++---- .../redux/walletconnect/WalletConnectState.kt | 2 +- core/res/src/main/res/values-ru/strings.xml | 1 + .../src/main/res/values-zh-rTW/strings.xml | 1 + core/res/src/main/res/values/strings.xml | 1 + 9 files changed, 59 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index e4520b39d6..2089abefa6 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -100,12 +100,19 @@ class DialogManager : StoreSubscriber { preparedData = state.dialog.data, context = context, ) - is WalletConnectDialog.UnsupportedNetwork -> + is WalletConnectDialog.UnsupportedNetwork -> { + val warning = if (state.dialog.networks.isNullOrEmpty()) { + context.getString(R.string.wallet_connect_scanner_error_unsupported_network) + } else { + context.getString(R.string.wallet_connect_error_unsupported_blockchains) + + state.dialog.networks + } SimpleAlertDialog.create( titleRes = R.string.wallet_connect_title, - messageRes = R.string.wallet_connect_scanner_error_unsupported_network, + message = warning, context = context, ) + } is WalletConnectDialog.SessionProposalDialog -> { SessionProposalDialog.create( sessionProposal = state.dialog.sessionProposal, diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt index 80d7ed0b09..01e3803798 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt @@ -1,15 +1,22 @@ package com.tangem.tap.domain.walletconnect2.data -import android.app.* -import com.tangem.tap.domain.walletconnect2.domain.* +import android.app.Application +import com.tangem.tap.domain.walletconnect2.domain.WalletConnectRepository +import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer import com.tangem.tap.domain.walletconnect2.domain.models.* -import com.walletconnect.android.* -import com.walletconnect.android.relay.* -import com.walletconnect.web3.wallet.client.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import timber.log.* -import javax.inject.* +import com.walletconnect.android.Core +import com.walletconnect.android.CoreClient +import com.walletconnect.android.relay.ConnectionType +import com.walletconnect.web3.wallet.client.Wallet +import com.walletconnect.web3.wallet.client.Web3Wallet +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject class WalletConnectRepositoryImpl @Inject constructor( private val application: Application, @@ -181,7 +188,7 @@ class WalletConnectRepositoryImpl @Inject constructor( userNamespaces = userNamespaces, ) if (missingNetworks.isNotEmpty()) { - Timber.e("Unsupported blockchains: $missingNetworks") + Timber.e("Not added blockchains: $missingNetworks") scope.launch { _events.emit( WalletConnectEvents.SessionApprovalError( diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index 03bd4e548e..21e5a73147 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -1,13 +1,16 @@ package com.tangem.tap.domain.walletconnect2.domain -import com.tangem.tap.common.extensions.* -import com.tangem.tap.domain.walletconnect.* +import com.tangem.tap.common.extensions.filterNotNull +import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper import com.tangem.tap.domain.walletconnect2.domain.models.* -import com.tangem.tap.features.details.ui.walletconnect.* -import com.tangem.utils.coroutines.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import timber.log.* +import com.tangem.tap.features.details.ui.walletconnect.WcSessionForScreen +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import timber.log.Timber class WalletConnectInteractor( private val handler: WalletConnectEventsHandler, @@ -47,6 +50,14 @@ class WalletConnectInteractor( when (wcEvent) { is WalletConnectEvents.SessionProposal -> { Timber.d("WC session proposal event received") + val unsupportedNetworks = wcEvent.chainIds + .filter { blockchainHelper.chainIdToNetworkIdOrNull(it) == null } + if (unsupportedNetworks.isNotEmpty()) { + val error = WalletConnectError.ApprovalErrorUnsupportedNetwork(unsupportedNetworks) + handler.onSessionRejected(error) + return@onEach + } + val networksFormatted = wcEvent.chainIds .mapNotNull { blockchainHelper.chainIdToFullNameOrNull(it) } .toString() @@ -57,12 +68,7 @@ class WalletConnectInteractor( is WalletConnectError.ApprovalErrorMissingNetworks -> { val missingNetworks = wcEvent.error.missingChains .map { blockchainHelper.chainIdToNetworkIdOrNull(it) } - val containsUnsupportedNetworks = missingNetworks.any { it == null } - if (containsUnsupportedNetworks) { - WalletConnectError.ApprovalErrorUnsupportedNetwork - } else { - WalletConnectError.ApprovalErrorAddNetwork(missingNetworks.filterNotNull()) - } + WalletConnectError.ApprovalErrorAddNetwork(missingNetworks.filterNotNull()) } else -> wcEvent.error } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt index 1f9b7f6771..35da4b88f8 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt @@ -3,7 +3,7 @@ package com.tangem.tap.domain.walletconnect2.domain.models sealed class WalletConnectError : Exception() { data class ApprovalErrorMissingNetworks(val missingChains: List) : WalletConnectError() data class ApprovalErrorAddNetwork(val networks: List) : WalletConnectError() - object ApprovalErrorUnsupportedNetwork : WalletConnectError() + data class ApprovalErrorUnsupportedNetwork(val unsupportedNetworks: List) : WalletConnectError() data class ExternalApprovalError(override val message: String?) : WalletConnectError() object WrongUserWallet : WalletConnectError() object UnsupportedMethod : WalletConnectError() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index b83b2ad75a..9632a15368 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -238,7 +238,7 @@ class WalletConnectMiddleware { return } val blockchain = action.blockchain.guard { - store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork)) + store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork())) return } val walletManager = getWalletManager( @@ -298,9 +298,12 @@ class WalletConnectMiddleware { ), ) } - - WalletConnectError.ApprovalErrorUnsupportedNetwork -> { - store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork)) + is WalletConnectError.ApprovalErrorUnsupportedNetwork -> { + store.dispatchOnMain( + GlobalAction.ShowDialog( + WalletConnectDialog.UnsupportedNetwork(action.error.unsupportedNetworks), + ), + ) } is WalletConnectError.ExternalApprovalError -> { store.dispatchOnMain( @@ -327,7 +330,7 @@ class WalletConnectMiddleware { scope.launch { walletConnectInteractor.continueWithRequest(action.sessionRequest) } } is WalletConnectAction.RejectUnsupportedRequest -> { - store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork)) + store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork())) } } } @@ -337,7 +340,7 @@ class WalletConnectMiddleware { chainId = chainId, peer = session.peerMeta, ).guard { - store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork)) + store.dispatchOnMain(GlobalAction.ShowDialog(WalletConnectDialog.UnsupportedNetwork())) return } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt index 71f4a14ca6..135f597dc1 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectState.kt @@ -91,7 +91,7 @@ data class WalletForSession( sealed class WalletConnectDialog : StateDialog { data class ClipboardOrScanQr(val clipboardUri: String) : WalletConnectDialog() object UnsupportedCard : WalletConnectDialog() - object UnsupportedNetwork : WalletConnectDialog() + data class UnsupportedNetwork(val networks: List? = null) : WalletConnectDialog() data class AddNetwork(val network: String) : WalletConnectDialog() object OpeningSessionRejected : WalletConnectDialog() object SessionTimeout : WalletConnectDialog() diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index e994de868f..4d71fe324b 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -457,6 +457,7 @@ Невозможно отправить транзакцию. Недостаточно средств. Не удалось установить сессию WalletConnect. Пожалуйста, повторите попытку позже. Не удалось установить сессию WalletConnect за отведённое время. Пожалуйста, повторите попытку позже. + Запрос на подключение через WalletConnect содержит неподдерживаемые блокчеины. Неподдерживаемые блокчеины:\n Cоединение с этим Dapp сервисом не может быть установлено из-за его технической реализации. Сеть %s не найдена. Пожалуйста, добавьте её и попробуйте заново. Вставить из буфера обмена diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index 08f4e9e68b..461c90bc77 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -436,6 +436,7 @@ 無法交易,無足夠資金 未能建立 WalletConnect 連接。請稍後再試 無法建立 WalletConnect 連接:超時錯誤。請稍後再試 + 會話請求包含不支持 WalletConnect 連接的區塊鏈。不支持的區塊鏈: 由於技術問題,無法與此 Dapp 建立連接 沒有 %s 網路,請先加入後再試一次 從剪貼板貼上 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 11ef0d6d75..695c74084b 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -449,6 +449,7 @@ Can\'t send transaction. Not enough funds. Failed to establish WalletConnect session. Please, try again later. Failed to establish WalletConnect session: timeout error. Please, try again later. + Session request contains unsupported blockchains for WalletConnect connection. Unsupported blockchains:\n Connection with this Dapp cannot be established due to its technical implementation. %s network not found. Please, add it first and try again. Paste from clipboard From c4488bee29e16fc29ded975c6a460ea5662e2707 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 15:48:32 +0400 Subject: [PATCH 10/27] Updated on 2026-08-14 --- .../details/redux/walletconnect/WalletConnectMiddleware.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 9632a15368..fd67e805d2 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -66,7 +66,7 @@ class WalletConnectMiddleware { walletConnectManager.restoreSessions(action.scanResponse) } is WalletConnectAction.HandleDeepLink -> { - if (!action.wcUri.isNullOrBlank() && WalletConnectManager.isCorrectWcUri(action.wcUri)) { + if (!action.wcUri.isNullOrBlank()) { store.dispatchOnMain(WalletConnectAction.OpenSession(action.wcUri)) } } From e5bd65c2852634c44569abd02edd6e70cff82b6f Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 16:29:25 +0400 Subject: [PATCH 11/27] Updated on 2026-08-14 --- .../walletconnect2/domain/WcSessionRequestConverter.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt index bc93e31462..fe67571134 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt @@ -130,7 +130,8 @@ class WcSessionRequestConverter( ): String? { return sessionsRepository.loadSessions(userWalletId) .firstOrNull { it.topic == sessionRequest.topic } - ?.accounts?.firstOrNull { it.chainId == sessionRequest.chainId && it.walletAddress == walletAddress } - ?.derivationPath + ?.accounts?.firstOrNull { + it.chainId == sessionRequest.chainId && it.walletAddress.lowercase() == walletAddress?.lowercase() + }?.derivationPath } } \ No newline at end of file From be017175348e245f5f3b7eec4aeac29a7992bff2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 18:09:08 +0400 Subject: [PATCH 12/27] Updated on 2026-08-14 --- .../tap/domain/walletconnect/WalletConnectSdkHelper.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index e315dace10..dc3169c18c 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -33,7 +33,6 @@ import com.tangem.tap.domain.walletconnect2.domain.models.EthTransactionData import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTradeOrder import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceTransferOrder import com.tangem.tap.features.details.redux.walletconnect.* -import com.tangem.tap.features.details.redux.walletconnect.WcEthTransactionType import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialogData import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionRequestDialogData import com.tangem.tap.store @@ -194,7 +193,12 @@ class WalletConnectSdkHelper { val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message(), cardId = cardId) return when (result) { is CompletionResult.Success -> { - HEX_PREFIX + result.data + HEX_PREFIX + EthereumUtils.prepareTransactionToSend( + signature = result.data.signature, + transactionToSign = dataToSign, + walletPublicKey = data.walletManager.wallet.publicKey, + blockchain = data.walletManager.wallet.blockchain, + ).toHexString() } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) } From 69f13c06fdd5168b2052d1138a921a52b371e8e1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 16 Jun 2023 18:20:05 +0400 Subject: [PATCH 13/27] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 50182bde55..f9be91dcce 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -83,9 +83,9 @@ class TapWalletManager( } private fun setupWalletConnectV2(userWallet: UserWallet) { - val cardId = if (userWallet.cardsInWallet.size == 1) { + val cardId = if (userWallet.scanResponse.card.backupStatus?.isActive != true) { userWallet.cardId - } else { + } else { // if wallet has backup, any card from wallet can be used to sign null } scope.launch { From 18f18f84cc188890433bbc5242df222f3fd9497e Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 09:28:53 +0400 Subject: [PATCH 14/27] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 4b14f8518a..8d89456b8c 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -77,7 +77,7 @@ walletConnectWeb3 = "1.8.0" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_4.7-243" +tangemBlockchainSdk = "release-app_4.7-245" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_4.7-268" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds From dfe2dc0a0e206235f4f458001cb21471a615d27f Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 14:01:07 +0400 Subject: [PATCH 15/27] Updated on 2026-08-14 --- .../tap/domain/walletconnect2/domain/WalletConnectInteractor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index 21e5a73147..ef202cd085 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -37,11 +37,11 @@ class WalletConnectInteractor( suspend fun startListening(userWalletId: String, cardId: String?) { this.userWalletId = userWalletId this.cardId = cardId + walletConnectRepository.updateSessions() coroutineScope { launch { subscribeToEvents() } launch { subscribeToSessions() } } - walletConnectRepository.updateSessions() } private suspend fun subscribeToEvents() { From c15c647db0a7b0cf7e10278149fa02c3bc74a4d3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 19:31:58 +0800 Subject: [PATCH 16/27] Updated on 2026-08-14 --- .../send/redux/middlewares/SendMiddleware.kt | 39 ++++++++++++------- .../send/redux/states/AddressPayIdState.kt | 16 ++++++++ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index c66271923f..d54adda3d5 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras import com.tangem.blockchain.blockchains.ton.TonTransactionExtras -import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder +import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder.XrpTransactionExtras import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.SimpleResult import com.tangem.common.core.TangemSdkError @@ -168,9 +168,7 @@ private fun sendTransaction( transactionExtras.xlmMemo?.memo?.let { txData = txData.copy(extras = StellarTransactionExtras(it)) } transactionExtras.binanceMemo?.memo?.let { txData = txData.copy(extras = BinanceTransactionExtras(it.toString())) } - transactionExtras.xrpDestinationTag?.tag?.let { - txData = txData.copy(extras = XrpTransactionBuilder.XrpTransactionExtras(it)) - } + transactionExtras.xrpDestinationTag?.tag?.let { txData = txData.copy(extras = XrpTransactionExtras(it)) } transactionExtras.cosmosMemoState?.memo?.let { txData = txData.copy(extras = CosmosTransactionExtras(it)) } transactionExtras.tonMemoState?.memo?.let { txData = txData.copy(extras = TonTransactionExtras(it)) } @@ -250,17 +248,10 @@ private fun sendTransaction( Analytics.send( Basic.TransactionSent( sentFrom = AnalyticsParam.TxSentFrom.Sell, - memoType = if (txData.extras != null) MemoType.Full else MemoType.Empty, - ), - ) - Analytics.send( - Token.Send.SelectedCurrency( - currency = when (mainCurrencyType) { - MainCurrencyType.FIAT -> CurrencyType.AppCurrency - MainCurrencyType.CRYPTO -> CurrencyType.AppCurrency - }, + memoType = getMemoType(transactionExtras), ), ) + Analytics.sendSelectedCurrencyEvent(mainCurrencyType) dispatch(WalletAction.TradeCryptoAction.FinishSelling(externalTransactionData.transactionId)) } else { Analytics.send( @@ -270,9 +261,10 @@ private fun sendTransaction( token = amountToSend.currencySymbol, feeType = feeType.convertToAnalyticsFeeType(), ), - memoType = if (txData.extras != null) MemoType.Full else MemoType.Empty, + memoType = getMemoType(transactionExtras), ), ) + Analytics.sendSelectedCurrencyEvent(mainCurrencyType) dispatch(NavigationAction.PopBackTo()) } scope.launch(Dispatchers.IO) { @@ -336,6 +328,25 @@ private fun sendTransaction( } } +private fun getMemoType(transactionExtras: TransactionExtrasState): MemoType { + return when { + transactionExtras.isEmpty() -> MemoType.Empty + transactionExtras.isNull() -> MemoType.Null + else -> MemoType.Full + } +} + +private fun Analytics.sendSelectedCurrencyEvent(mainCurrencyType: MainCurrencyType) { + send( + Token.Send.SelectedCurrency( + currency = when (mainCurrencyType) { + MainCurrencyType.FIAT -> CurrencyType.AppCurrency + MainCurrencyType.CRYPTO -> CurrencyType.Token + }, + ), + ) +} + private fun updateFeedbackManagerInfo( walletManager: WalletManager, amountToSend: Amount, 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 b1e3261e67..9f0851e06d 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 @@ -34,6 +34,21 @@ data class TransactionExtrasState( val cosmosMemoState: CosmosMemoState? = null, ) : IdStateHolder { override val stateId: StateId = StateId.TRANSACTION_EXTRAS + + fun isNull(): Boolean { + return xlmMemo == null && binanceMemo == null && xrpDestinationTag == null && tonMemoState == null && + cosmosMemoState == null + } + + fun isEmpty(): Boolean { + val isXlmEmpty = xlmMemo?.viewFieldValue?.value?.isEmpty() ?: false + val isBinanceEmpty = binanceMemo?.viewFieldValue?.value?.isEmpty() ?: false + val isXrpEmpty = xrpDestinationTag?.viewFieldValue?.value?.isEmpty() ?: false + val isTonEmpty = tonMemoState?.viewFieldValue?.value?.isEmpty() ?: false + val isCosmosEmpty = cosmosMemoState?.viewFieldValue?.value?.isEmpty() ?: false + + return isXlmEmpty || isBinanceEmpty || isXrpEmpty || isTonEmpty || isCosmosEmpty + } } enum class XlmMemoType { @@ -105,6 +120,7 @@ data class TonMemoState( val memo: String? = null, val error: TransactionExtraError? = null, ) + data class CosmosMemoState( val viewFieldValue: InputViewValue = InputViewValue(""), val memo: String? = null, From 7dd02865025fd58c2d3f7d1b0140f9e268a35f02 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jun 2023 23:32:18 +0800 Subject: [PATCH 17/27] Updated on 2026-08-14 --- .../tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt index f40f0d38dc..273d52d384 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/utils/WalletDataOperations.kt @@ -82,7 +82,7 @@ internal fun WalletDataModel.getAvailableActions( internal fun WalletDataModel.shouldShowMultipleAddress(): Boolean { val listOfAddresses = walletAddresses?.list.orEmpty() - return listOfAddresses.size > 1 + return listOfAddresses.size > 1 && currency.blockchain != Blockchain.BitcoinCash } internal fun WalletDataModel.assembleWarnings( From 673e812fd1f36662a960a0fc3591c9e0ff7057e7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 20 Jun 2023 22:10:23 +0800 Subject: [PATCH 18/27] Updated on 2026-08-14 --- .../tangem/tap/features/shop/data/DefaultShopRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt b/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt index 8f61a43c5f..74505b69d3 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/data/DefaultShopRepository.kt @@ -25,8 +25,8 @@ internal class DefaultShopRepository( .fold( onSuccess = ShopResponse::isOrderingAvailable, onFailure = { - Timber.e("Server error. isShopifyOrderingAvailable returns default value (false)") - false + Timber.e("Server error. isShopifyOrderingAvailable returns default value (true)") + true }, ) } From 150436c3ff4626be827cf6568498526f9d1c5b97 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 21 Jun 2023 17:48:18 +0800 Subject: [PATCH 19/27] Updated on 2026-08-14 --- .../impl/presentation/viewmodels/AddCustomTokenViewModel.kt | 3 ++- .../java/com/tangem/domain/common/extensions/Blockchain.kt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt index 5ccb8e66e6..47245502cf 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt @@ -207,7 +207,8 @@ internal class AddCustomTokenViewModel @Inject constructor( val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown) return listOf(defaultNetwork) + Blockchain.values() .filter { blockchain -> - reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true + reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true && + blockchain != Blockchain.Cardano } .sortedBy(Blockchain::fullName) .map(::createNetworkSelectorItem) diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index 151aecafc4..c891e19e44 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -173,5 +173,6 @@ fun Blockchain.isSupportedInApp(): Boolean { } private val excludedBlockchains = listOf( + Blockchain.Ducatus, Blockchain.Unknown, ) \ No newline at end of file From e644fbf181a76c8cbca67992199e3a2264c66b58 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 21 Jun 2023 13:58:02 +0300 Subject: [PATCH 20/27] Updated on 2026-08-14 --- .../implementation/DefaultWalletCurrenciesManager.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index f344f46d4a..0bbd76b7bc 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -1,13 +1,10 @@ package com.tangem.tap.domain.walletCurrencies.implementation import com.tangem.blockchain.common.DerivationStyle -import com.tangem.common.CompletionResult -import com.tangem.common.flatMap -import com.tangem.common.fold -import com.tangem.common.map -import com.tangem.domain.models.scan.CardDTO +import com.tangem.common.* import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.util.UserWalletId +import com.tangem.domain.models.scan.CardDTO import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.builders.WalletStoreBuilder @@ -103,7 +100,7 @@ internal class DefaultWalletCurrenciesManager( .flatMap { updateWalletStores(userWallet, remainingCurrencies.toBlockchainNetworks()) } - .map { + .doOnResult { saveUserCurrencies(card, remainingCurrencies) } } From 6310754739454d8ba032683063c6d0befef84be7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 21 Jun 2023 16:14:45 +0300 Subject: [PATCH 21/27] Updated on 2026-08-14 --- .../walletconnect/WalletConnectMiddleware.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index fd67e805d2..c42aa9f320 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -306,13 +306,16 @@ class WalletConnectMiddleware { ) } is WalletConnectError.ExternalApprovalError -> { - store.dispatchOnMain( - GlobalAction.ShowDialog( - AppDialog.SimpleOkWarningDialog( - message = action.error.message ?: "", + val message = action.error.message + if (!message.isNullOrEmpty()) { + store.dispatchOnMain( + GlobalAction.ShowDialog( + AppDialog.SimpleOkWarningDialog( + message = message, + ), ), - ), - ) + ) + } } else -> Unit } From e1ff73091211f803877442ebb4a2b38e8a8e1946 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Jun 2023 12:21:57 +0300 Subject: [PATCH 22/27] Updated on 2026-08-14 --- .../presentation/AddCustomTokenFragment.kt | 10 +- .../presentation/ui/AddCustomTokenContent.kt | 9 +- .../presentation/ui/AddCustomTokenScreen.kt | 7 +- .../ui/AddCustomTokenTestContent.kt | 29 +--- .../ui/walletconnect/QrScanFragment.kt | 15 +- .../impl/presentation/TokensListFragment.kt | 10 +- .../impl/presentation/ui/TokensListScreen.kt | 3 +- .../feature/referral/ReferralFragment.kt | 12 +- .../feature/referral/ui/ReferralScreen.kt | 133 +++++++----------- .../wallet/presentation/WalletFragment.kt | 3 - .../organizetokens/OrganizeTokensScreen.kt | 3 +- .../router/DefaultWalletRouter.kt | 12 +- .../presentation/wallet/ui/WalletScreen.kt | 4 +- 13 files changed, 113 insertions(+), 137 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt index f4478fc4fc..a203e348dd 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt @@ -4,9 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.transition.TransitionInflater @@ -25,8 +26,6 @@ import dagger.hilt.android.AndroidEntryPoint internal class AddCustomTokenFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } - with(TransitionInflater.from(requireContext())) { enterTransition = inflateTransition(R.transition.fade) exitTransition = inflateTransition(R.transition.fade) @@ -41,7 +40,10 @@ internal class AddCustomTokenFragment : Fragment() { } TangemTheme { - AddCustomTokenScreen(stateHolder = viewModel.uiState) + AddCustomTokenScreen( + modifier = Modifier.systemBarsPadding(), + stateHolder = viewModel.uiState, + ) } } } diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt index e57d82cc15..55afd696af 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt @@ -8,11 +8,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.FabPosition import androidx.compose.material.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity @@ -33,11 +29,12 @@ import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCu [REDACTED_AUTHOR] */ @Composable -internal fun AddCustomTokenContent(state: AddCustomTokenStateHolder.Content) { +internal fun AddCustomTokenContent(state: AddCustomTokenStateHolder.Content, modifier: Modifier = Modifier) { BackHandler(onBack = state.onBackButtonClick) var floatingButtonHeight by remember { mutableStateOf(0.dp) } Scaffold( + modifier = modifier, topBar = { AddCustomTokenToolbar( title = state.toolbar.title, diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt index 71d079e899..eb099e7ee8 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.customtoken.impl.presentation.ui import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider @@ -15,10 +16,10 @@ import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTok [REDACTED_AUTHOR] */ @Composable -internal fun AddCustomTokenScreen(stateHolder: AddCustomTokenStateHolder) { +internal fun AddCustomTokenScreen(stateHolder: AddCustomTokenStateHolder, modifier: Modifier = Modifier) { when (stateHolder) { - is AddCustomTokenStateHolder.Content -> AddCustomTokenContent(state = stateHolder) - is AddCustomTokenStateHolder.TestContent -> AddCustomTokenTestContent(state = stateHolder) + is AddCustomTokenStateHolder.Content -> AddCustomTokenContent(stateHolder, modifier) + is AddCustomTokenStateHolder.TestContent -> AddCustomTokenTestContent(stateHolder, modifier) } } diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt index c23fa86835..9304675ad7 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt @@ -1,31 +1,11 @@ package com.tangem.tap.features.customtoken.impl.presentation.ui import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.BottomSheetScaffold -import androidx.compose.material.BottomSheetScaffoldState -import androidx.compose.material.BottomSheetState -import androidx.compose.material.BottomSheetValue -import androidx.compose.material.Divider -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.FabPosition -import androidx.compose.material.Text -import androidx.compose.material.rememberBottomSheetScaffoldState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.key -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -59,7 +39,7 @@ import kotlinx.coroutines.launch */ @OptIn(ExperimentalMaterialApi::class) @Composable -internal fun AddCustomTokenTestContent(state: AddCustomTokenStateHolder.TestContent) { +internal fun AddCustomTokenTestContent(state: AddCustomTokenStateHolder.TestContent, modifier: Modifier = Modifier) { val coroutineScope = rememberCoroutineScope() val bottomSheetScaffoldState = rememberBottomSheetScaffoldState( bottomSheetState = BottomSheetState(initialValue = BottomSheetValue.Collapsed), @@ -77,6 +57,7 @@ internal fun AddCustomTokenTestContent(state: AddCustomTokenStateHolder.TestCont var floatingButtonHeight by remember { mutableStateOf(0.dp) } BottomSheetScaffold( + modifier = modifier, sheetContent = { SheetContent( coroutineScope = coroutineScope, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt index a08b9af8b2..91a8e803b3 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/QrScanFragment.kt @@ -24,7 +24,7 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } + setFitSystemWindows(fit = true) activity?.onBackPressedDispatcher?.addCallback( this, object : OnBackPressedCallback(true) { @@ -47,6 +47,11 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler { scannerView?.stopCamera() } + override fun onDestroy() { + super.onDestroy() + setFitSystemWindows(fit = false) + } + override fun onResume() { super.onResume() scannerView?.setResultHandler(this) @@ -55,7 +60,7 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler { override fun handleResult(result: Result) { store.dispatch(NavigationAction.PopBackTo()) - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, false) } + setFitSystemWindows(fit = false) if (!result.text.isNullOrBlank()) { store.dispatch(WalletConnectAction.OpenSession(result.text)) } @@ -83,4 +88,10 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler { private fun requestPermission() { requestPermissions(arrayOf(Manifest.permission.CAMERA), CameraView.PERMISSION_REQUEST_CODE) } + + private fun setFitSystemWindows(fit: Boolean) { + activity?.window?.let { + WindowCompat.setDecorFitsSystemWindows(it, fit) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt index e5ac57cfc8..8af509f84f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt @@ -4,9 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.transition.TransitionInflater @@ -25,8 +26,6 @@ import dagger.hilt.android.AndroidEntryPoint internal class TokensListFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } - with(TransitionInflater.from(requireContext())) { enterTransition = inflateTransition(R.transition.fade) exitTransition = inflateTransition(R.transition.fade) @@ -41,7 +40,10 @@ internal class TokensListFragment : Fragment() { } TangemTheme { - TokensListScreen(stateHolder = viewModel.uiState) + TokensListScreen( + modifier = Modifier.systemBarsPadding(), + stateHolder = viewModel.uiState, + ) } } } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt index d378d6ba75..44e620b8ac 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt @@ -56,12 +56,13 @@ import kotlinx.coroutines.flow.flowOf [REDACTED_AUTHOR] */ @Composable -internal fun TokensListScreen(stateHolder: TokensListStateHolder) { +internal fun TokensListScreen(stateHolder: TokensListStateHolder, modifier: Modifier = Modifier) { BackHandler(onBack = stateHolder.toolbarState.onBackButtonClick) var floatingButtonHeight by remember { mutableStateOf(value = 0.dp) } Scaffold( + modifier = modifier, topBar = { TokensListToolbar(state = stateHolder.toolbarState) }, floatingActionButton = { if (stateHolder is TokensListStateHolder.ManageContent) { diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt index 938566bd50..b04b901b66 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt @@ -4,11 +4,13 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView -import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.transition.TransitionInflater +import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.referral.presentation.R import com.tangem.feature.referral.router.ReferralRouter import com.tangem.feature.referral.ui.ReferralScreen @@ -28,13 +30,17 @@ class ReferralFragment : Fragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } viewModel.setRouter(ReferralRouter(fragmentManager = WeakReference(parentFragmentManager))) viewModel.onScreenOpened() return ComposeView(inflater.context).apply { isTransitionGroup = true setContent { - ReferralScreen(stateHolder = viewModel.uiState) + TangemTheme { + ReferralScreen( + modifier = Modifier.systemBarsPadding(), + stateHolder = viewModel.uiState, + ) + } } } } diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt index 7f1ff6b6a8..7c3e8b2ddf 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt @@ -5,41 +5,11 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.LocalOverscrollConfiguration import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.BottomSheetScaffold -import androidx.compose.material.BottomSheetState -import androidx.compose.material.BottomSheetValue -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.Icon -import androidx.compose.material.Snackbar -import androidx.compose.material.SnackbarDuration -import androidx.compose.material.SnackbarHost -import androidx.compose.material.SnackbarHostState -import androidx.compose.material.SnackbarResult -import androidx.compose.material.Text -import androidx.compose.material.rememberBottomSheetScaffoldState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -63,9 +33,7 @@ import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.referral.models.DemoModeException import com.tangem.feature.referral.models.ReferralStateHolder -import com.tangem.feature.referral.models.ReferralStateHolder.ErrorSnackbar -import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoContentState -import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState +import com.tangem.feature.referral.models.ReferralStateHolder.* import com.tangem.feature.referral.presentation.R import com.valentinilk.shimmer.shimmer import kotlinx.coroutines.launch @@ -77,47 +45,46 @@ import kotlinx.coroutines.launch */ @OptIn(ExperimentalMaterialApi::class) @Composable -internal fun ReferralScreen(stateHolder: ReferralStateHolder) { +internal fun ReferralScreen(stateHolder: ReferralStateHolder, modifier: Modifier = Modifier) { val coroutineScope = rememberCoroutineScope() val bottomSheetScaffoldState = rememberBottomSheetScaffoldState( bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed), ) - TangemTheme { - BottomSheetScaffold( - sheetContent = { - AgreementBottomSheetContent( - url = when (val state = stateHolder.referralInfoState) { - is ReferralInfoState.NonParticipantContent -> state.url - is ReferralInfoState.ParticipantContent -> state.url - is ReferralInfoState.Loading -> "" - }, - ) - }, - scaffoldState = bottomSheetScaffoldState, - sheetShape = RoundedCornerShape( - topStart = TangemTheme.dimens.radius16, - topEnd = TangemTheme.dimens.radius16, - ), - sheetElevation = TangemTheme.dimens.elevation24, - sheetPeekHeight = TangemTheme.dimens.size0, - content = { - ReferralContent( - stateHolder = stateHolder, - onAgreementClick = { - stateHolder.analytics.onAgreementClicked.invoke() - coroutineScope.launch { - if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) { - bottomSheetScaffoldState.bottomSheetState.expand() - } else { - bottomSheetScaffoldState.bottomSheetState.collapse() - } + BottomSheetScaffold( + modifier = modifier, + sheetContent = { + AgreementBottomSheetContent( + url = when (val state = stateHolder.referralInfoState) { + is ReferralInfoState.NonParticipantContent -> state.url + is ReferralInfoState.ParticipantContent -> state.url + is ReferralInfoState.Loading -> "" + }, + ) + }, + scaffoldState = bottomSheetScaffoldState, + sheetShape = RoundedCornerShape( + topStart = TangemTheme.dimens.radius16, + topEnd = TangemTheme.dimens.radius16, + ), + sheetElevation = TangemTheme.dimens.elevation24, + sheetPeekHeight = TangemTheme.dimens.size0, + content = { + ReferralContent( + stateHolder = stateHolder, + onAgreementClick = { + stateHolder.analytics.onAgreementClicked.invoke() + coroutineScope.launch { + if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) { + bottomSheetScaffoldState.bottomSheetState.expand() + } else { + bottomSheetScaffoldState.bottomSheetState.collapse() } - }, - ) - }, - ) - } + } + }, + ) + }, + ) } @OptIn(ExperimentalFoundationApi::class) @@ -487,7 +454,7 @@ private fun Preview_ReferralScreen_Participant_InLightTheme() { TangemTheme(isDark = false) { ReferralScreen( stateHolder = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), + headerState = HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.ParticipantContent( award = "10 USDT", networkName = "Tron", @@ -499,7 +466,7 @@ private fun Preview_ReferralScreen_Participant_InLightTheme() { url = "", ), errorSnackbar = null, - analytics = ReferralStateHolder.Analytics( + analytics = Analytics( onAgreementClicked = {}, onCopyClicked = {}, onShareClicked = {}, @@ -515,7 +482,7 @@ private fun Preview_ReferralScreen_Participant_InDarkTheme() { TangemTheme(isDark = true) { ReferralScreen( stateHolder = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), + headerState = HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.ParticipantContent( award = "10 USDT", networkName = "Tron", @@ -527,7 +494,7 @@ private fun Preview_ReferralScreen_Participant_InDarkTheme() { url = "", ), errorSnackbar = null, - analytics = ReferralStateHolder.Analytics( + analytics = Analytics( onAgreementClicked = {}, onCopyClicked = {}, onShareClicked = {}, @@ -543,7 +510,7 @@ private fun Preview_ReferralScreen_NonParticipant_InLightTheme() { TangemTheme(isDark = false) { ReferralScreen( stateHolder = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), + headerState = HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.NonParticipantContent( award = "10 USDT", networkName = "Tron", @@ -552,7 +519,7 @@ private fun Preview_ReferralScreen_NonParticipant_InLightTheme() { onParticipateClicked = {}, ), errorSnackbar = null, - analytics = ReferralStateHolder.Analytics( + analytics = Analytics( onAgreementClicked = {}, onCopyClicked = {}, onShareClicked = {}, @@ -568,7 +535,7 @@ private fun Preview_ReferralScreen_NonParticipant_InDarkTheme() { TangemTheme(isDark = true) { ReferralScreen( stateHolder = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), + headerState = HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.NonParticipantContent( award = "10 USDT", networkName = "Tron", @@ -577,7 +544,7 @@ private fun Preview_ReferralScreen_NonParticipant_InDarkTheme() { onParticipateClicked = {}, ), errorSnackbar = null, - analytics = ReferralStateHolder.Analytics( + analytics = Analytics( onAgreementClicked = {}, onCopyClicked = {}, onShareClicked = {}, @@ -593,10 +560,10 @@ private fun Preview_ReferralScreen_Loading_InLightTheme() { TangemTheme(isDark = false) { ReferralScreen( stateHolder = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), + headerState = HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.Loading, errorSnackbar = null, - analytics = ReferralStateHolder.Analytics( + analytics = Analytics( onAgreementClicked = {}, onCopyClicked = {}, onShareClicked = {}, @@ -612,10 +579,10 @@ private fun Preview_ReferralScreen_Loading_InDarkTheme() { TangemTheme(isDark = true) { ReferralScreen( stateHolder = ReferralStateHolder( - headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), + headerState = HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.Loading, errorSnackbar = null, - analytics = ReferralStateHolder.Analytics( + analytics = Analytics( onAgreementClicked = {}, onCopyClicked = {}, onShareClicked = {}, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt index 1bc2cd04fd..04e93bf88f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/WalletFragment.kt @@ -6,7 +6,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView -import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.router.InnerWalletRouter @@ -32,8 +31,6 @@ internal class WalletFragment : Fragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } - with(TransitionInflater.from(requireContext())) { enterTransition = inflateTransition(R.transition.slide_right) exitTransition = inflateTransition(R.transition.fade) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt index e626eb0029..f4b5bb65d0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt @@ -13,8 +13,9 @@ import com.tangem.feature.wallet.presentation.common.WalletPreviewData import com.tangem.feature.wallet.presentation.common.state.TokenListState @Composable -internal fun OrganizeTokensScreen(state: OrganizeTokensStateHolder) { +internal fun OrganizeTokensScreen(state: OrganizeTokensStateHolder, modifier: Modifier = Modifier) { Scaffold( + modifier = modifier, topBar = { TopBar(state.header) }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index f2768ed116..b963f8f7b7 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -1,7 +1,9 @@ package com.tangem.feature.wallet.presentation.router import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.fragment.app.Fragment import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController @@ -32,7 +34,10 @@ internal class DefaultWalletRouter : InnerWalletRouter { ) { composable(WalletScreens.WALLET.name) { val viewModel = hiltViewModel().apply { router = this@DefaultWalletRouter } - WalletScreen(state = viewModel.uiState) + WalletScreen( + modifier = Modifier.systemBarsPadding(), + state = viewModel.uiState, + ) } composable(WalletScreens.ORGANIZE_TOKENS.name) { @@ -41,7 +46,10 @@ internal class DefaultWalletRouter : InnerWalletRouter { val viewModel: OrganizeTokensViewModel = hiltViewModel() .apply { router = this@DefaultWalletRouter } - OrganizeTokensScreen(state = viewModel.uiState) + OrganizeTokensScreen( + modifier = Modifier.systemBarsPadding(), + state = viewModel.uiState, + ) } } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index ba17e6e692..098d1e1e45 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui import androidx.activity.compose.BackHandler import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletHeader @@ -14,10 +15,11 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletHeader [REDACTED_AUTHOR] */ @Composable -internal fun WalletScreen(state: WalletStateHolder) { +internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifier) { BackHandler(onBack = state.onBackClick) Scaffold( + modifier = modifier, topBar = { WalletHeader(config = state.headerConfig) }, ) { // TODO: [REDACTED_TASK_KEY] Design a body with tokens and transactions From 23dc56c8b287acd5b0116c5238e0a1f70119a8de Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Jun 2023 21:08:10 +0800 Subject: [PATCH 23/27] Updated on 2026-08-14 --- .../impl/presentation/viewmodels/AddCustomTokenViewModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt index 47245502cf..6429affe5e 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt @@ -271,7 +271,9 @@ internal class AddCustomTokenViewModel @Inject constructor( type = DerivationPathSelectorType.CUSTOM, ), ) + Blockchain.values() - .filter { blockchain -> blockchain.isSupportedInApp() && !blockchain.isTestnet() } + .filter { blockchain -> + blockchain.isSupportedInApp() && !blockchain.isTestnet() && blockchain != Blockchain.Cardano + } .sortedBy(Blockchain::fullName) .map(::createDerivationPathSelectorAdditionalItem) } From b9e3753ae8c8e1d28f292e3db52baca55635929f Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 23 Jun 2023 16:32:13 +0300 Subject: [PATCH 24/27] Updated on 2026-08-14 --- .../impl/presentation/ui/components/AddCustomTokenForm.kt | 2 -- .../presentation/viewmodels/AddCustomTokenViewModel.kt | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt index 0051e2e6c4..0090ef8223 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt @@ -8,7 +8,6 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -161,7 +160,6 @@ private fun SelectorField(model: AddCustomTokenSelectorField) { expanded = isExpanded && isEnabled, onDismissRequest = { isExpanded = false }, ) { - FocusRequester model.items.forEachIndexed { index, item -> DropdownMenuItem( onClick = { diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt index 6429affe5e..297bf37f54 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt @@ -41,6 +41,7 @@ import com.tangem.wallet.BuildConfig import com.tangem.wallet.R import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -613,7 +614,11 @@ internal class AddCustomTokenViewModel @Inject constructor( private inner class ActionsHandler(private val featureRouter: CustomTokenRouter) { fun onBackButtonClick() { - featureRouter.popBackStack() + viewModelScope.launch(dispatchers.main) { + // need delay before close, cause crashed in compose PopUpMenu as + delay(timeMillis = 100) + featureRouter.popBackStack() + } } fun onContactAddressValueChange(enteredValue: String) { From 847a430533aab17b69fc2cbc82f153a2bb76513a Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 26 Jun 2023 09:30:18 +0300 Subject: [PATCH 25/27] Updated on 2026-08-14 --- .../tap/common/redux/global/GlobalState.kt | 1 + .../BiometricUserWalletsListManager.kt | 4 +- .../DefaultWalletAmountsRepository.kt | 71 ++++++++----------- .../middlewares/MultiWalletMiddleware.kt | 5 +- .../redux/middlewares/WalletMiddleware.kt | 11 +-- .../com/tangem/tap/proxy/AppStateHolder.kt | 1 + 6 files changed, 42 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index c9f2314efc..c4becfb45b 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -15,6 +15,7 @@ import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager import org.rekotlin.StateType data class GlobalState( + @Deprecated("Use scan response from selected user wallet") val scanResponse: ScanResponse? = null, val onboardingState: OnboardingState = OnboardingState(), val cardVerifiedOnline: Boolean = false, diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index 78f74e0c3d..4ea180e270 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -118,7 +118,9 @@ internal class BiometricUserWalletsListManager( } .flatMap { updatedUserWallet -> saveInternal(updatedUserWallet, changeSelectedUserWallet = false) - .map { updatedUserWallet } + } + .flatMap { + get(userWalletId) } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index e276bd51db..22dd64bff1 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -7,16 +7,11 @@ import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.extensions.Result.Failure import com.tangem.blockchain.extensions.Result.Success -import com.tangem.common.CompletionResult -import com.tangem.common.catching +import com.tangem.common.* import com.tangem.common.core.TangemError -import com.tangem.common.flatMap -import com.tangem.common.flatMapOnFailure -import com.tangem.common.fold -import com.tangem.common.map import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.domain.common.util.hasDerivation import com.tangem.domain.common.util.UserWalletId +import com.tangem.domain.common.util.hasDerivation import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.TestActions import com.tangem.tap.common.entities.FiatCurrency @@ -25,15 +20,7 @@ import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.walletStores.WalletStoresError import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository -import com.tangem.tap.domain.walletStores.repository.implementation.utils.replaceWalletStore -import com.tangem.tap.domain.walletStores.repository.implementation.utils.replaceWalletStores -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithAmounts -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithDemoAmounts -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithError -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithFiatRates -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithMissedDerivation -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithRent -import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithUnreachable +import com.tangem.tap.domain.walletStores.repository.implementation.utils.* import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage import com.tangem.tap.domain.walletStores.storage.WalletStoresStorage import com.tangem.tap.features.demo.DemoHelper @@ -45,13 +32,8 @@ import com.tangem.tap.features.wallet.models.getPendingTransactions import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.store import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay +import kotlinx.coroutines.* import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.withContext import timber.log.Timber import java.math.BigDecimal import kotlin.time.Duration @@ -200,37 +182,40 @@ internal class DefaultWalletAmountsRepository( walletStore: WalletStoreModel, walletManager: WalletManager?, ): CompletionResult { - val hasMissedDerivations = with(walletStore) { + val isDerivationMissed = with(walletStore) { derivationPath != null && !scanResponse.hasDerivation(blockchain, derivationPath.rawPath) } return when { - hasMissedDerivations -> { + isDerivationMissed -> { updateWalletStoreWithMissedDerivation(walletStore) } walletManager == null -> { updateWalletStoreWithUnreachable(walletStore) } else -> { - updateWalletManager(scanResponse, walletManager).map { - updateWalletManagerInStorage( - userWalletId, - walletManager, - ) - }.flatMap { - updateWalletStoreWithAmounts( - walletStore = walletStore, - updatedWallet = walletManager.wallet, - // FIXME: move DemoHelper to Demo core module maybe - isDemo = DemoHelper.isDemoCardId(scanResponse.card.cardId), - ) - }.flatMap { fetchWalletStoreRentIfNeeded(walletStore, walletManager) }.flatMapOnFailure { error -> - updateWalletStoreWithError( - walletStore = walletStore, - wallet = walletManager.wallet, - error = error, - ) - } + updateWalletManager(scanResponse, walletManager) + .map { + updateWalletManagerInStorage(userWalletId, walletManager) + } + .flatMap { + updateWalletStoreWithAmounts( + walletStore = walletStore, + updatedWallet = walletManager.wallet, + // FIXME: move DemoHelper to Demo core module maybe + isDemo = DemoHelper.isDemoCardId(scanResponse.card.cardId), + ) + } + .flatMap { + fetchWalletStoreRentIfNeeded(walletStore, walletManager) + } + .flatMapOnFailure { error -> + updateWalletStoreWithError( + walletStore = walletStore, + wallet = walletManager.wallet, + error = error, + ) + } } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 607d8c63c4..d86a41c389 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -9,7 +9,7 @@ import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken import com.tangem.tap.common.extensions.addContext import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification -import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -114,7 +114,8 @@ class MultiWalletMiddleware { ) } .doOnSuccess { updatedUserWallet -> - store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) + store.dispatchWithMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) + store.dispatchWithMain(GlobalAction.SaveScanResponse(updatedUserWallet.scanResponse)) store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index c7bde94141..d7a0da7703 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -17,6 +17,7 @@ import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.* 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.domain.TapError @@ -97,12 +98,12 @@ class WalletMiddleware { Timber.e("Unable to create wallet, no user wallet selected") return@launch } + val updatedScanResponse = selectedUserWallet.scanResponse.copy( + card = result.data, + ) + store.dispatchWithMain(GlobalAction.SaveScanResponse(updatedScanResponse)) userWalletsListManager.update(selectedUserWallet.walletId) { userWallet -> - userWallet.copy( - scanResponse = userWallet.scanResponse.copy( - card = result.data, - ), - ) + userWallet.copy(scanResponse = updatedScanResponse) } } is CompletionResult.Failure -> Unit diff --git a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt index aab3cfd808..35c2d83718 100644 --- a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt @@ -19,6 +19,7 @@ import javax.inject.Inject */ class AppStateHolder @Inject constructor() { + @Deprecated("Use scan response from selected user wallet") var scanResponse: ScanResponse? = null var walletState: WalletState? = null var userTokensRepository: UserTokensRepository? = null From 8bc6c921f3dbf6e951a3896bddf5633426cbfd35 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 26 Jun 2023 12:21:44 +0300 Subject: [PATCH 26/27] Updated on 2026-08-14 --- .idea/codeStyles/Project.xml | 5 +---- .../wallet/presentation/router/DefaultWalletRouter.kt | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 7fc608245b..0db8c6d7c9 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -13,9 +13,6 @@ -