Updated on 2026-08-14
This commit is contained in:
commit
ddd5ed14e7
10 changed files with 56 additions and 52 deletions
|
|
@ -103,7 +103,7 @@ internal class BiometricUserWalletsListManager(
|
|||
|
||||
override suspend fun save(userWallet: UserWallet, canOverride: Boolean): CompletionResult<Unit> {
|
||||
return if (canOverride) {
|
||||
saveInternal(userWallet, changeSelectedUserWallet = true)
|
||||
saveInternal(userWallet, changeSelectedUserWallet = true, canOverridePublicInfo = false)
|
||||
} else {
|
||||
val isWalletSaved = state.value.userWallets
|
||||
.any {
|
||||
|
|
@ -113,7 +113,7 @@ internal class BiometricUserWalletsListManager(
|
|||
if (isWalletSaved) {
|
||||
CompletionResult.Failure(UserWalletsListError.WalletAlreadySaved)
|
||||
} else {
|
||||
saveInternal(userWallet, changeSelectedUserWallet = true)
|
||||
saveInternal(userWallet, changeSelectedUserWallet = true, canOverridePublicInfo = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ internal class BiometricUserWalletsListManager(
|
|||
update(storedUserWallet)
|
||||
}
|
||||
.flatMap { updatedUserWallet ->
|
||||
saveInternal(updatedUserWallet, changeSelectedUserWallet = false)
|
||||
saveInternal(updatedUserWallet, changeSelectedUserWallet = false, canOverridePublicInfo = true)
|
||||
}
|
||||
.flatMap {
|
||||
get(userWalletId)
|
||||
|
|
@ -181,10 +181,11 @@ internal class BiometricUserWalletsListManager(
|
|||
private suspend fun saveInternal(
|
||||
userWallet: UserWallet,
|
||||
changeSelectedUserWallet: Boolean,
|
||||
canOverridePublicInfo: Boolean,
|
||||
): CompletionResult<Unit> {
|
||||
return saveEncryptionKeyIfNotNull(userWallet)
|
||||
.flatMap { sensitiveInformationRepository.save(userWallet, encryptionKey = it) }
|
||||
.flatMap { publicInformationRepository.save(userWallet) }
|
||||
.flatMap { publicInformationRepository.save(userWallet, canOverridePublicInfo) }
|
||||
.map {
|
||||
if (changeSelectedUserWallet) {
|
||||
selectedUserWalletRepository.set(userWallet.walletId)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||
|
||||
internal interface UserWalletsPublicInformationRepository {
|
||||
suspend fun save(userWallet: UserWallet): CompletionResult<Unit>
|
||||
suspend fun save(userWallet: UserWallet, canOverride: Boolean): CompletionResult<Unit>
|
||||
|
||||
suspend fun getAll(): CompletionResult<List<UserWalletPublicInformation>>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,18 +24,23 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
|||
Types.newParameterizedType(List::class.java, UserWalletPublicInformation::class.java),
|
||||
)
|
||||
|
||||
override suspend fun save(userWallet: UserWallet): CompletionResult<Unit> {
|
||||
override suspend fun save(userWallet: UserWallet, canOverride: Boolean): CompletionResult<Unit> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
getAll()
|
||||
.flatMap { savedInformation ->
|
||||
val infoToSave = withContext(Dispatchers.Default) {
|
||||
savedInformation.addOrReplace(userWallet.publicInformation) {
|
||||
userWallet.walletId == it.walletId
|
||||
}
|
||||
getAll().flatMap { savedWalletsInformation ->
|
||||
val infoToSave = if (canOverride) {
|
||||
savedWalletsInformation.addOrReplace(userWallet.publicInformation) {
|
||||
it.walletId == userWallet.walletId
|
||||
}
|
||||
} else {
|
||||
if (savedWalletsInformation.none { it.walletId == userWallet.walletId }) {
|
||||
savedWalletsInformation + userWallet.publicInformation
|
||||
} else {
|
||||
return@withContext CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
save(infoToSave)
|
||||
}
|
||||
|
||||
save(infoToSave)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,48 +1,35 @@
|
|||
package com.tangem.tap.features.details.ui.cardsettings.coderecovery
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.core.ui.theme.AppThemeModeHolder
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import javax.inject.Inject
|
||||
|
||||
class AccessCodeRecoveryFragment : Fragment(), StoreSubscriber<DetailsState> {
|
||||
@AndroidEntryPoint
|
||||
class AccessCodeRecoveryFragment : ComposeFragment(), StoreSubscriber<DetailsState> {
|
||||
|
||||
private val viewModel = AccessCodeRecoveryViewModel(store)
|
||||
|
||||
private var screenState: MutableState<AccessCodeRecoveryScreenState> =
|
||||
mutableStateOf(viewModel.updateState(store.state.detailsState.cardSettingsState?.accessCodeRecovery))
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@Inject
|
||||
override lateinit var appThemeModeHolder: AppThemeModeHolder
|
||||
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.fade)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
TangemTheme {
|
||||
AccessCodeRecoveryScreen(
|
||||
state = screenState.value,
|
||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier) {
|
||||
AccessCodeRecoveryScreen(
|
||||
state = screenState.value,
|
||||
onBackClick = { store.dispatch(NavigationAction.PopBackTo()) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ internal class DefaultUserTokensStore(
|
|||
) : UserTokensStore, StringKeyDataStoreDecorator<UserWalletId, UserTokensResponse>(dataStore) {
|
||||
|
||||
override fun provideStringKey(key: UserWalletId): String {
|
||||
return key.stringValue
|
||||
return "user_tokens_${key.stringValue}"
|
||||
}
|
||||
}
|
||||
|
|
@ -77,6 +77,7 @@ data class CryptoCurrencyStatus(
|
|||
val amountToCreateAccount: BigDecimal,
|
||||
override val priceChange: BigDecimal?,
|
||||
override val fiatRate: BigDecimal?,
|
||||
override val networkAddress: NetworkAddress?,
|
||||
) : Status(isError = false) {
|
||||
|
||||
override val amount: BigDecimal = BigDecimal.ZERO
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ internal class CurrencyStatusOperations(
|
|||
null -> CryptoCurrencyStatus.Loading
|
||||
is NetworkStatus.MissedDerivation -> createMissedDerivationStatus()
|
||||
is NetworkStatus.Unreachable -> createUnreachableStatus()
|
||||
is NetworkStatus.NoAccount -> createNoAccountStatus(status.amountToCreateAccount)
|
||||
is NetworkStatus.NoAccount -> createNoAccountStatus(status)
|
||||
is NetworkStatus.Verified -> createStatus(status)
|
||||
}
|
||||
}
|
||||
|
|
@ -28,11 +28,12 @@ internal class CurrencyStatusOperations(
|
|||
private fun createUnreachableStatus(): CryptoCurrencyStatus.Unreachable =
|
||||
CryptoCurrencyStatus.Unreachable(priceChange = quote?.priceChange, fiatRate = quote?.fiatRate)
|
||||
|
||||
private fun createNoAccountStatus(amount: BigDecimal): CryptoCurrencyStatus.NoAccount =
|
||||
private fun createNoAccountStatus(status: NetworkStatus.NoAccount): CryptoCurrencyStatus.NoAccount =
|
||||
CryptoCurrencyStatus.NoAccount(
|
||||
amountToCreateAccount = amount,
|
||||
amountToCreateAccount = status.amountToCreateAccount,
|
||||
priceChange = quote?.priceChange,
|
||||
fiatRate = quote?.fiatRate,
|
||||
networkAddress = status.address,
|
||||
)
|
||||
|
||||
private fun createStatus(status: NetworkStatus.Verified): CryptoCurrencyStatus.Status {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import junit.framework.TestCase.assertEquals
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
internal class GetTokenListUseCaseTest {
|
||||
|
|
@ -29,6 +30,7 @@ internal class GetTokenListUseCaseTest {
|
|||
private val dispatchers = TestingCoroutineDispatcherProvider()
|
||||
private val userWalletId = UserWalletId(value = null)
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `when list ungrouped and unsorted then correct token list should be returned`() = runTest {
|
||||
// Given
|
||||
|
|
@ -115,6 +117,7 @@ internal class GetTokenListUseCaseTest {
|
|||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `when tokens getting failed on second emit then error should be received`() = runTest {
|
||||
// Given
|
||||
|
|
@ -141,6 +144,7 @@ internal class GetTokenListUseCaseTest {
|
|||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `when list grouped then correct token list should be received`() = runTest {
|
||||
val expectedResult = listOf(
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ internal object MockTokensStates {
|
|||
priceChange = MockQuotes.quote7.priceChange,
|
||||
fiatRate = MockQuotes.quote7.fiatRate,
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = null,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -72,6 +73,7 @@ internal object MockTokensStates {
|
|||
priceChange = MockQuotes.quote8.priceChange,
|
||||
fiatRate = MockQuotes.quote8.fiatRate,
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = null,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -81,6 +83,7 @@ internal object MockTokensStates {
|
|||
priceChange = MockQuotes.quote9.priceChange,
|
||||
fiatRate = MockQuotes.quote9.fiatRate,
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = null,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -90,6 +93,7 @@ internal object MockTokensStates {
|
|||
priceChange = MockQuotes.quote10.priceChange,
|
||||
fiatRate = MockQuotes.quote10.fiatRate,
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = null,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -59,12 +59,13 @@ internal class SwapRepositoryImpl @Inject constructor(
|
|||
return withContext(coroutineDispatcher.io) {
|
||||
val rates = tangemTechApi.getRates(currencyId.lowercase(), addedTokens.joinToString(",")).rates
|
||||
val ethRate = rates[ETHEREUM_ID]
|
||||
rates.mapValues {
|
||||
if (it.key == OPTIMISM_ID || it.key == ARBITRUM_ID) {
|
||||
ethRate ?: 0.0
|
||||
} else {
|
||||
it.value
|
||||
if (tokenIds.contains(OPTIMISM_ID) || tokenIds.contains(ARBITRUM_ID)) {
|
||||
rates.toMutableMap().apply {
|
||||
put(OPTIMISM_ID, ethRate ?: 0.0)
|
||||
put(ARBITRUM_ID, ethRate ?: 0.0)
|
||||
}
|
||||
} else {
|
||||
rates
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue