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 6b870386be..01625dc4f2 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -139,8 +139,9 @@ class DialogManager : StoreSubscriber { title = context.getString(state.dialog.titleRes, state.dialog.currencySymbol), message = context.getString( state.dialog.messageRes, - state.dialog.currencySymbol, state.dialog.currencyTitle, + state.dialog.currencySymbol, + state.dialog.networkName, ), context = context, ) diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt b/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt index fc362509c3..a65014a580 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppDialog.kt @@ -43,6 +43,7 @@ sealed class AppDialog : StateDialog { data class TokensAreLinkedDialog( val currencyTitle: String, val currencySymbol: String, + val networkName: String, ) : AppDialog() { val messageRes: Int = R.string.token_details_unable_hide_alert_message val titleRes: Int = R.string.token_details_unable_hide_alert_title diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt index ff53145651..1935d1f5d6 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt @@ -30,7 +30,7 @@ private fun internalReduce(action: Action, state: AppState): NavigationState { when { // Destroy the activity if it invoked for the same activity. Prevents overwriting to null if there is a // new scan from the background [REDACTED_TASK_KEY] - navState.activity?.get() == navigationAction.activity.get() -> navState.copy(activity = null) + navState.activity?.get() == navigationAction.activity.get() -> NavigationState() else -> navState } } diff --git a/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt index a164e0dde1..395f26e868 100644 --- a/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt @@ -19,6 +19,8 @@ import com.tangem.sdk.extensions.* import com.tangem.sdk.nfc.NfcManager import com.tangem.sdk.storage.create import com.tangem.tap.foregroundActivityObserver +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.runBlocking import javax.inject.Inject import javax.inject.Singleton @@ -30,6 +32,7 @@ import javax.inject.Singleton @Singleton internal class DefaultCardSdkProvider @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, + private val dispatchers: CoroutineDispatcherProvider, ) : CardSdkProvider, CardSdkOwner { private val observer = Observer() @@ -39,12 +42,12 @@ internal class DefaultCardSdkProvider @Inject constructor( override val sdk: TangemSdk get() = holder?.sdk ?: tryToRegisterWithForegroundActivity() - override fun register(activity: FragmentActivity) { + override fun register(activity: FragmentActivity) = runBlocking(dispatchers.mainImmediate) { if (activity.isDestroyed || activity.isFinishing || activity.isChangingConfigurations) { val message = "Tangem SDK owner registration skipped: activity is destroyed or finishing" analyticsEventHandler.send(TangemSdkWarningEvent(message)) Log.info { message } - return + return@runBlocking } if (holder != null) { @@ -58,7 +61,7 @@ internal class DefaultCardSdkProvider @Inject constructor( Log.info { "Tangem SDK owner registered" } } - private fun tryToRegisterWithForegroundActivity(): TangemSdk { + private fun tryToRegisterWithForegroundActivity(): TangemSdk = runBlocking(dispatchers.mainImmediate) { val warning = "Tangem SDK holder is null, trying to recreate it with foreground activity" analyticsEventHandler.send(TangemSdkWarningEvent(warning)) Log.warning { warning } @@ -83,7 +86,7 @@ internal class DefaultCardSdkProvider @Inject constructor( error(error) } - return sdk + return@runBlocking sdk } private fun initialize(activity: FragmentActivity) { diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/TangemSdkManager.kt index e3de1dc4a7..0f5e408f5e 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/TangemSdkManager.kt @@ -33,6 +33,10 @@ interface TangemSdkManager { val userCodeRequestPolicy: UserCodeRequestPolicy + suspend fun checkCanUseBiometry(awaitInitialization: Boolean = true): Boolean + + suspend fun checkNeedEnrollBiometrics(awaitInitialization: Boolean = true): Boolean + suspend fun scanProduct( cardId: String? = null, messageRes: Int? = null, diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt index 72b578cea9..00bacdbe26 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt @@ -3,9 +3,11 @@ package com.tangem.tap.domain.sdk.impl import android.content.res.Resources import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import com.tangem.Log import com.tangem.Message import com.tangem.TangemSdk import com.tangem.common.* +import com.tangem.common.authentication.AuthenticationManager import com.tangem.common.authentication.keystore.KeystoreManager import com.tangem.common.card.FirmwareVersion import com.tangem.common.core.* @@ -38,16 +40,21 @@ import com.tangem.tap.domain.twins.CreateSecondTwinWalletTask import com.tangem.tap.domain.twins.FinalizeTwinTask import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import kotlin.coroutines.resume -@Suppress("TooManyFunctions") +@Suppress("TooManyFunctions", "LargeClass") class DefaultTangemSdkManager( private val cardSdkConfigRepository: CardSdkConfigRepository, private val resources: Resources, ) : TangemSdkManager { + private val awaitInitializationMutex = Mutex() + private val tangemSdk: TangemSdk get() = cardSdkConfigRepository.sdk @@ -73,6 +80,42 @@ class DefaultTangemSdkManager( override val userCodeRequestPolicy: UserCodeRequestPolicy get() = tangemSdk.config.userCodeRequestPolicy + override suspend fun checkNeedEnrollBiometrics(awaitInitialization: Boolean): Boolean { + return try { + needEnrollBiometrics + } catch (e: TangemSdkError.AuthenticationNotInitialized) { + Log.error { + "Trying to access `needEnrollBiometrics` flag when authentication manager is not initialized: " + + if (awaitInitialization) "awaiting initialization" else "failing" + } + + if (awaitInitialization) { + awaitAuthenticationManagerInitialization().needEnrollBiometrics + } else { + throw e + } + } + } + + override suspend fun checkCanUseBiometry(awaitInitialization: Boolean): Boolean { + return try { + canUseBiometry + } catch (e: TangemSdkError.AuthenticationNotInitialized) { + Log.error { + "Trying to access `canUseBiometry` flag when authentication manager is not initialized: " + + if (awaitInitialization) "awaiting initialization" else "failing" + } + + if (awaitInitialization) { + val manager = awaitAuthenticationManagerInitialization() + + manager.canAuthenticate || manager.needEnrollBiometrics + } else { + throw e + } + } + } + override suspend fun scanProduct( cardId: String?, messageRes: Int?, @@ -288,6 +331,26 @@ class DefaultTangemSdkManager( tangemSdk.config.userCodeRequestPolicy = policy } + private suspend fun awaitAuthenticationManagerInitialization(): AuthenticationManager { + return awaitInitializationMutex.withLock { + var attemps = 0 + + do { + if (tangemSdk.authenticationManager.isInitialized) { + break + } else { + if (attemps++ >= MAX_INITIALIZE_ATTEMPTS) { + error("Can't initialize authentication manager after $MAX_INITIALIZE_ATTEMPTS attempts") + } else { + delay(timeMillis = 200) + } + } + } while (true) + + tangemSdk.authenticationManager + } + } + // region Twin-specific override suspend fun createFirstTwinWallet( @@ -335,6 +398,8 @@ class DefaultTangemSdkManager( // endregion companion object { + private const val MAX_INITIALIZE_ATTEMPTS = 10 + @Deprecated("Use [DefaultCardSdkProvider] instead") val config = Config( linkedTerminal = true, diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt index 7c5585c68b..dcc850f798 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt @@ -28,9 +28,11 @@ class MockTangemSdkManager( private val resources: Resources, ) : TangemSdkManager { - override val canUseBiometry = false + private var userCodeRequestPolicyInternal: UserCodeRequestPolicy = UserCodeRequestPolicy.Default - override val needEnrollBiometrics = false + override val canUseBiometry: Boolean = false + + override val needEnrollBiometrics: Boolean = false override val keystoreManager = DummyKeystoreManager() @@ -39,7 +41,9 @@ class MockTangemSdkManager( override val userCodeRequestPolicy: UserCodeRequestPolicy get() = userCodeRequestPolicyInternal - private var userCodeRequestPolicyInternal: UserCodeRequestPolicy = UserCodeRequestPolicy.Default + override suspend fun checkCanUseBiometry(awaitInitialization: Boolean): Boolean = canUseBiometry + + override suspend fun checkNeedEnrollBiometrics(awaitInitialization: Boolean): Boolean = needEnrollBiometrics override suspend fun scanProduct( cardId: String?, diff --git a/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt b/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt index 00f7f53887..6a84f8cd30 100644 --- a/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt @@ -7,5 +7,5 @@ internal class DefaultLegacySettingsRepository( private val tangemSdkManager: TangemSdkManager, ) : LegacySettingsRepository { - override fun canUseBiometry(): Boolean = tangemSdkManager.canUseBiometry + override suspend fun canUseBiometry(): Boolean = tangemSdkManager.checkCanUseBiometry() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index c82a82d087..ba234b662c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -37,7 +37,10 @@ import com.tangem.utils.coroutines.saveIn import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.rekotlin.Action @@ -265,7 +268,6 @@ class DetailsMiddleware { .onEach { needEnrollBiometrics -> store.dispatchWithMain(DetailsAction.AppSettings.BiometricsStatusChanged(needEnrollBiometrics)) } - .flowOn(Dispatchers.IO) .launchIn(lifecycleScope) .saveIn(checkBiometricsStatusJobHolder) } diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 5a915b21d5..68b87d064f 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -76,7 +76,9 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen, state: AppS }, createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup, appSettingsState = AppSettingsState( - isBiometricsAvailable = tangemSdkManager.canUseBiometry, + isBiometricsAvailable = runBlocking { + tangemSdkManager.checkCanUseBiometry() + }, saveWallets = action.shouldSaveUserWallets, saveAccessCodes = runBlocking { store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index f03dc73425..3aca958d05 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -99,7 +99,7 @@ object OnboardingHelper { } // When should not save user wallets but device has biometry and save wallet screen has not been shown, // then open save wallet screen - tangemSdkManager.canUseBiometry && settingsRepository.shouldShowSaveUserWalletScreen() -> { + tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen() -> { proceedWithScanResponse(scanResponse, backupCardsIds, hasBackupError) delay(timeMillis = 1_200) diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index 45eb5225a2..4069551f22 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -91,10 +91,10 @@ internal class SaveWalletMiddleware { store.dispatchOnMain(NavigationAction.OpenBiometricsSettings) } - private fun allowToUseBiometrics(state: SaveWalletState) { - if (tangemSdkManager.needEnrollBiometrics) { - store.dispatchOnMain(SaveWalletAction.EnrollBiometrics) - return + private fun allowToUseBiometrics(state: SaveWalletState) = scope.launch { + if (tangemSdkManager.checkNeedEnrollBiometrics()) { + store.dispatchWithMain(SaveWalletAction.EnrollBiometrics) + return@launch } if (state.backupInfo != null) { @@ -104,24 +104,22 @@ internal class SaveWalletMiddleware { Analytics.send(MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On)) } - scope.launch { - /* + /* - * because it will be automatically saved on UserWalletsListManager switch - */ - val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) - val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { - val error = IllegalStateException("No selected user wallet") - Timber.e(error, "Unable to save user wallet") - store.dispatchWithMain( - SaveWalletAction.AllowToUseBiometrics.Error(TangemSdkError.ExceptionError(error)), - ) - return@launch - } + * because it will be automatically saved on UserWalletsListManager switch + */ + val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager) + val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard { + val error = IllegalStateException("No selected user wallet") + Timber.e(error, "Unable to save user wallet") + store.dispatchWithMain( + SaveWalletAction.AllowToUseBiometrics.Error(TangemSdkError.ExceptionError(error)), + ) + return@launch + } - handleSuccessAllowing(selectedUserWallet) - }.saveIn(saveWalletJobHolder) - } + handleSuccessAllowing(selectedUserWallet) + }.saveIn(saveWalletJobHolder) private suspend fun handleSuccessAllowing(userWallet: UserWallet) { store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt index 27418f3d01..f401253e1e 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt @@ -29,9 +29,13 @@ internal class DefaultTokensListRouter : TokensListRouter { store.dispatchNotification(R.string.contract_address_copied_message) } - override fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String) { + override fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String, networkName: String) { store.dispatchDialogShow( - dialog = AppDialog.TokensAreLinkedDialog(currencyTitle = tokenName, currencySymbol = tokenSymbol), + dialog = AppDialog.TokensAreLinkedDialog( + currencyTitle = tokenName, + currencySymbol = tokenSymbol, + networkName = networkName, + ), ) } diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt index 34b5379b48..a11e584564 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/TokensListRouter.kt @@ -19,8 +19,9 @@ internal interface TokensListRouter { * * @param tokenName token name * @param tokenSymbol token brief name + * @param networkName blockchain network full name */ - fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String) + fun openUnableHideMainTokenAlert(tokenName: String, tokenSymbol: String, networkName: String) /** * Open alert to remove wallet diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt index 53867da367..4874bc303c 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt @@ -365,6 +365,7 @@ internal class TokensListViewModel @Inject constructor( router.openUnableHideMainTokenAlert( tokenName = blockchain.name, tokenSymbol = blockchain.currency, + networkName = blockchain.fullName, ) } else if (isAddedOnMainScreen) { router.openRemoveWalletAlert( diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt index 52a2e4cc6f..919be8e848 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt @@ -5,6 +5,7 @@ import okio.Timeout import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import timber.log.Timber internal class ApiResponseCallDelegate( private val wrappedCall: Call, @@ -20,7 +21,9 @@ internal class ApiResponseCallDelegate( override fun timeout(): Timeout = wrappedCall.timeout() override fun isExecuted(): Boolean = wrappedCall.isExecuted override fun isCanceled(): Boolean = wrappedCall.isCanceled - override fun cancel() { wrappedCall.cancel() } + override fun cancel() { + wrappedCall.cancel() + } private inner class ApiResponseCallback( private val responseCallback: Callback>, @@ -33,7 +36,15 @@ internal class ApiResponseCallDelegate( } override fun onFailure(call: Call, t: Throwable) { - val error = t.toApiError() + val error = try { + t.toApiError() + } catch (e: ApiResponseError) { + Timber.e(e, "error map toApiError") + e + } catch (e: Exception) { + Timber.e(e, "onFailure UnknownException") + ApiResponseError.UnknownException(e) + } val safeResponse = apiError(error) responseCallback.onResponse(this@ApiResponseCallDelegate, Response.success(safeResponse)) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt index cfd2146441..22162b76b4 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt @@ -73,10 +73,16 @@ sealed class ApiResponseError : Exception() { } /** Represents a network error, typically when there's no connectivity. */ - data object NetworkException : ApiResponseError() + @Suppress("UnusedPrivateMember") + data object NetworkException : ApiResponseError() { + private fun readResolve(): Any = NetworkException + } /** Represents a timeout error, typically when the server takes too long to respond. */ - data object TimeoutException : ApiResponseError() + @Suppress("UnusedPrivateMember") + data object TimeoutException : ApiResponseError() { + private fun readResolve(): Any = TimeoutException + } /** * Represents an unexpected exception that doesn't fall into one of the other categories. diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt index 92a5af0ac5..f696275bc3 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt @@ -2,6 +2,7 @@ package com.tangem.datasource.api.common.response import kotlinx.coroutines.TimeoutCancellationException import retrofit2.Response +import timber.log.Timber import java.net.ConnectException import java.net.SocketTimeoutException import java.net.UnknownHostException @@ -16,10 +17,15 @@ internal fun Response.toSafeApiResponse(): ApiResponse { } else { val code = ApiResponseError.HttpException.Code.values .firstOrNull { it.code == code() } - val e = if (code == null) { - ApiResponseError.UnknownException(IllegalArgumentException("Unknown error status code: ${code()}")) - } else { - ApiResponseError.HttpException(code, message(), errorBody()?.string()) + val e = try { + if (code == null) { + ApiResponseError.UnknownException(IllegalArgumentException("Unknown error status code: ${code()}")) + } else { + ApiResponseError.HttpException(code, message(), errorBody()?.string()) + } + } catch (e: Exception) { + Timber.e(e, "UnknownException occured") + ApiResponseError.UnknownException(e) } apiError(e) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt index 076c60da41..34ae262e6d 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationWithBackground.kt @@ -172,7 +172,7 @@ private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvid title = resourceReference(id = R.string.main_swap_changelly_promotion_title), subtitle = resourceReference( id = R.string.main_swap_changelly_promotion_message, - formatArgs = wrappedList("1", "2"), + formatArgs = wrappedList("1", "2", "3"), ), iconResId = R.drawable.img_swap_promo, backgroundResId = R.drawable.img_swap_promo_blue_banner_background, @@ -180,7 +180,7 @@ private class NotificationWithBackgroundPreviewProvider : PreviewParameterProvid NotificationConfig( title = resourceReference( id = R.string.token_swap_changelly_promotion_title, - formatArgs = wrappedList("1", "2"), + formatArgs = wrappedList("1"), ), subtitle = stringReference( "Swap multiple currencies between any chains you wish. Swap multiple " + diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/CanUseBiometryUseCase.kt b/domain/settings/src/main/java/com/tangem/domain/settings/CanUseBiometryUseCase.kt index 390c70dcc4..880f941db8 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/CanUseBiometryUseCase.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/CanUseBiometryUseCase.kt @@ -4,5 +4,5 @@ import com.tangem.domain.settings.repositories.LegacySettingsRepository class CanUseBiometryUseCase(private val legacySettingsRepository: LegacySettingsRepository) { - operator fun invoke(): Boolean = legacySettingsRepository.canUseBiometry() + suspend operator fun invoke(): Boolean = legacySettingsRepository.canUseBiometry() } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/LegacySettingsRepository.kt b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/LegacySettingsRepository.kt index 9e1dc7cf3a..e1f1b8ebb7 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/LegacySettingsRepository.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/LegacySettingsRepository.kt @@ -2,5 +2,5 @@ package com.tangem.domain.settings.repositories interface LegacySettingsRepository { - fun canUseBiometry(): Boolean + suspend fun canUseBiometry(): Boolean } \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 41817d438f..b7ef29922c 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -89,7 +89,7 @@ markdown = "0.7.2" # region Tangem tangemBlockchainSdk = "release-app_5.12-698" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.12-369" +tangemCardSdk = "release-app_5.12-371" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ # endregion Tangem