Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-17 10:59:26 +02:00
parent 98d0d9c75e
commit b1c19eff9e
21 changed files with 538 additions and 52 deletions

View file

@ -18,6 +18,7 @@ import com.tangem.domain.account.status.usecase.GetBackupProblematicWalletForAdd
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.addressbook.interactor.GetVerifiedContactsInteractor
import com.tangem.domain.addressbook.model.Contact
import com.tangem.domain.addressbook.usecase.IsAddressBookCompatibleUseCase
import com.tangem.domain.addressbook.usecase.SyncAddressBooksUseCase
import com.tangem.domain.feedback.SendBackupProblemEmailUseCase
import com.tangem.domain.models.account.AccountStatus
@ -88,6 +89,7 @@ internal class SendDestinationModel @Inject constructor(
private val addressBookSendAnalytics: AddressBookSendAnalytics,
private val syncAddressBooksUseCase: SyncAddressBooksUseCase,
private val addressBookFeatureToggles: AddressBookFeatureToggles,
isAddressBookCompatibleUseCase: IsAddressBookCompatibleUseCase,
getVerifiedContactsInteractor: GetVerifiedContactsInteractor,
contactSelectionListener: ContactSelectionListener,
) : Model(), SendDestinationClickIntents {
@ -105,6 +107,11 @@ internal class SendDestinationModel @Inject constructor(
.flowOn(dispatchers.default)
.stateIn(modelScope, SharingStarted.Eagerly, emptyList())
private val isAddressBookCompatible: StateFlow<Boolean> =
isAddressBookCompatibleUseCase(userWalletId)
.flowOn(dispatchers.default)
.stateIn(modelScope, SharingStarted.Eagerly, initialValue = true)
val addressSelectorNavigation = SlotNavigation<MatchedContact>()
val addressQuery: StateFlow<String> = uiState
.map { (it as? DestinationUM.Content)?.addressTextField?.value.orEmpty() }
@ -118,7 +125,8 @@ internal class SendDestinationModel @Inject constructor(
*/
val showAddContact: StateFlow<Boolean> =
if ((params as? DestinationBlockParams)?.isAddContactAvailable == true) {
combine(uiState, contacts) { state, contactList ->
combine(uiState, contacts, isAddressBookCompatible) { state, contactList, isCompatible ->
if (!isCompatible) return@combine false
val address = (state as? DestinationUM.Content)?.addressTextField ?: return@combine false
if (address.contactName != null) return@combine false // sent via a contact
val networkId = cryptoCurrency.network.rawId

View file

@ -16,6 +16,7 @@ import com.tangem.domain.account.status.usecase.GetBackupProblematicWalletForAdd
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.addressbook.interactor.GetVerifiedContactsInteractor
import com.tangem.domain.addressbook.model.*
import com.tangem.domain.addressbook.usecase.IsAddressBookCompatibleUseCase
import com.tangem.domain.addressbook.usecase.SyncAddressBooksUseCase
import com.tangem.domain.feedback.SendBackupProblemEmailUseCase
import com.tangem.domain.models.currency.CryptoCurrency
@ -94,6 +95,7 @@ internal class SendDestinationModelTest {
private val sendBackupProblemEmailUseCase: SendBackupProblemEmailUseCase = mockk(relaxed = true)
private val getVerifiedContactsInteractor: GetVerifiedContactsInteractor = mockk(relaxed = true)
private val syncAddressBooksUseCase: SyncAddressBooksUseCase = mockk(relaxed = true)
private val isAddressBookCompatibleUseCase: IsAddressBookCompatibleUseCase = mockk(relaxed = true)
private val addressBookFeatureToggles: AddressBookFeatureToggles = mockk(relaxed = true)
private val contactSelectionListener: ContactSelectionListener = mockk(relaxed = true)
private val addressBookSendAnalytics: AddressBookSendAnalytics = mockk(relaxed = true)
@ -490,6 +492,25 @@ internal class SendDestinationModelTest {
assertThat(sut.showAddContact.value).isEqualTo(model.expectedShown)
}
@Test
fun `GIVEN book newer than supported WHEN fresh address entered THEN add-contact hidden`() = runTest {
// Arrange
coEvery {
validateWalletAddressUseCase(any(), any(), any(), any<List<CryptoCurrencyAddress>>(), any())
} returns AddressValidation.Success.Valid.right()
every { getVerifiedContactsInteractor.getVerifiedContacts(any(), any()) } returns flowOf(emptyList())
every { isAddressBookCompatibleUseCase(testUserWalletId) } returns flowOf(false)
val sut = buildBlockModel(isAddContactAvailable = true)
advanceUntilIdle()
// Act
sut.onRecipientAddressValueChange("0xFresh", EnterAddressSource.InputField)
advanceUntilIdle()
// Assert — a newer book can't be written, so saving the recipient is never offered.
assertThat(sut.showAddContact.value).isFalse()
}
private fun provideTestModels() = listOf(
// not available -> never shown, even for a fresh valid address
AddContactModel(
@ -667,6 +688,7 @@ internal class SendDestinationModelTest {
addressBookSendAnalytics = addressBookSendAnalytics,
syncAddressBooksUseCase = syncAddressBooksUseCase,
addressBookFeatureToggles = addressBookFeatureToggles,
isAddressBookCompatibleUseCase = isAddressBookCompatibleUseCase,
getVerifiedContactsInteractor = getVerifiedContactsInteractor,
contactSelectionListener = contactSelectionListener,
)