Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-28 16:08:31 +05:00
parent a0f6e4a008
commit 6c8b59c569
12 changed files with 288 additions and 66 deletions

View file

@ -44,14 +44,6 @@ internal class DefaultNotificationsRepository @Inject constructor(
return appPreferencesStore.getSyncOrNull(PreferencesKeys.NOTIFICATIONS_APPLICATION_ID_KEY)
}
override suspend fun setNotificationsEnabledForWallet(walletId: String, enabled: Boolean) =
withContext(dispatchers.io) {
tangemTechApi.setNotificationsEnabled(
walletId = walletId,
body = WalletBody(notifyStatus = enabled),
).getOrThrow()
}
override suspend fun associateApplicationIdWithWallets(appId: String, wallets: List<String>) =
withContext(dispatchers.io) {
tangemTechApi.associateApplicationIdWithWallets(
@ -62,10 +54,6 @@ internal class DefaultNotificationsRepository @Inject constructor(
).getOrThrow()
}
override suspend fun isNotificationsEnabledForWallet(walletId: String): Boolean = withContext(dispatchers.io) {
tangemTechApi.getWalletById(walletId).getOrThrow().notifyStatus
}
override suspend fun setWalletName(walletId: String, walletName: String) = withContext(dispatchers.io) {
tangemTechApi.updateWallet(
walletId,

View file

@ -103,26 +103,6 @@ class DefaultNotificationsRepositoryTest {
assertThat(result).isEqualTo(expectedAppId)
}
@Test
fun `GIVEN wallet id and enabled status WHEN setNotificationsEnabledForWallet THEN updates notification status`() =
runTest {
// GIVEN
val walletId = "test-wallet-id"
val enabled = true
coEvery {
tangemTechApi.setNotificationsEnabled(
walletId,
WalletBody(notifyStatus = enabled),
)
} returns ApiResponse.Success(Unit)
// WHEN
repository.setNotificationsEnabledForWallet(walletId, enabled)
// THEN
coVerify { tangemTechApi.setNotificationsEnabled(walletId, WalletBody(notifyStatus = enabled)) }
}
@Test
fun `GIVEN application id and wallet list WHEN associateApplicationIdWithWallets THEN associates them`() = runTest {
// GIVEN
@ -142,26 +122,6 @@ class DefaultNotificationsRepositoryTest {
coVerify { tangemTechApi.associateApplicationIdWithWallets(appId, wallets.map { WalletIdBody(it) }) }
}
@Test
fun `GIVEN wallet id WHEN isNotificationsEnabledForWallet THEN returns notification status`() = runTest {
// GIVEN
val walletId = "test-wallet-id"
val expectedStatus = true
coEvery { tangemTechApi.getWalletById(walletId) } returns ApiResponse.Success(
WalletResponse(
notifyStatus = expectedStatus,
name = "Test Wallet",
id = walletId,
),
)
// WHEN
val result = repository.isNotificationsEnabledForWallet(walletId)
// THEN
assertThat(result).isEqualTo(expectedStatus)
}
@Test
fun `GIVEN wallet id and name WHEN setWalletName THEN updates wallet name`() = runTest {
// GIVEN

View file

@ -34,4 +34,12 @@ dependencies {
/** Other deps */
implementation(deps.androidx.datastore)
implementation(deps.arrow.core)
/** tests */
testImplementation(deps.test.junit)
testImplementation(deps.test.coroutine)
testImplementation(deps.test.truth)
testImplementation(deps.test.mockk)
testImplementation(deps.moshi)
testImplementation(deps.moshi.kotlin)
}

View file

@ -6,6 +6,7 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.MarkUserWalletWasCreatedBody
import com.tangem.datasource.api.tangemTech.models.SeedPhraseNotificationDTO
import com.tangem.datasource.api.tangemTech.models.SeedPhraseNotificationDTO.Status
import com.tangem.datasource.api.tangemTech.models.WalletBody
import com.tangem.datasource.local.datastore.RuntimeStateStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
@ -21,11 +22,9 @@ import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.utils.WEEK_MILLIS
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
typealias SeedPhraseNotificationsStatuses = Map<UserWalletId, SeedPhraseNotificationsStatus>
@ -231,4 +230,44 @@ internal class DefaultWalletsRepository(
)
}
}
override suspend fun isNotificationsEnabled(userWalletId: UserWalletId, force: Boolean): Boolean =
withContext(dispatchers.io) {
if (force) {
return@withContext loadAndSaveNotificationsEnabled(userWalletId)
}
val localValue = appPreferencesStore.getObjectMap<Boolean>(PreferencesKeys.NOTIFICATIONS_ENABLED_STATES_KEY)
.map { it[userWalletId.stringValue] }
.firstOrNull()
localValue ?: loadAndSaveNotificationsEnabled(userWalletId)
}
override suspend fun setNotificationsEnabled(userWalletId: UserWalletId, isEnabled: Boolean) {
withContext(dispatchers.io) {
tangemTechApi.setNotificationsEnabled(
walletId = userWalletId.stringValue,
body = WalletBody(notifyStatus = isEnabled),
).getOrThrow()
setNotificationsEnabledLocally(userWalletId, isEnabled)
}
}
private suspend fun loadAndSaveNotificationsEnabled(userWalletId: UserWalletId): Boolean {
val walletResponse = tangemTechApi.getWalletById(walletId = userWalletId.stringValue).getOrThrow()
val isEnabled = walletResponse.notifyStatus
setNotificationsEnabledLocally(userWalletId, isEnabled)
return isEnabled
}
private suspend fun setNotificationsEnabledLocally(userWalletId: UserWalletId, isEnabled: Boolean) {
appPreferencesStore.editData {
it.setObjectMap(
key = PreferencesKeys.NOTIFICATIONS_ENABLED_STATES_KEY,
value = it.getObjectMap<Boolean>(PreferencesKeys.NOTIFICATIONS_ENABLED_STATES_KEY)
.plus(userWalletId.stringValue to isEnabled),
)
}
}
}

View file

@ -0,0 +1,176 @@
package com.tangem.data.wallets
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import com.squareup.moshi.Moshi
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.WalletBody
import com.tangem.datasource.api.tangemTech.models.WalletResponse
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.*
import io.mockk.coEvery
import io.mockk.coVerify
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
class DefaultWalletsRepositoryTest {
private lateinit var repository: DefaultWalletsRepository
private val preferencesDataStore = mockk<DataStore<Preferences>>(relaxed = true)
private val appPreferenceStore = AppPreferencesStore(
moshi = Moshi.Builder().build(),
dispatchers = TestingCoroutineDispatcherProvider(),
preferencesDataStore = preferencesDataStore,
)
private lateinit var tangemTechApi: TangemTechApi
private lateinit var dispatchers: CoroutineDispatcherProvider
private val testWalletId = UserWalletId("1234567890abcdef")
private val testWalletResponse = WalletResponse(
id = testWalletId.stringValue,
notifyStatus = true,
)
@Before
fun setup() {
tangemTechApi = mockk()
dispatchers = TestingCoroutineDispatcherProvider()
repository = DefaultWalletsRepository(
appPreferencesStore = appPreferenceStore,
tangemTechApi = tangemTechApi,
userWalletsStore = mockk(),
seedPhraseNotificationVisibilityStore = mockk(),
dispatchers = dispatchers,
)
}
@Test
fun `GIVEN force is true WHEN isNotificationsEnabled THEN should fetch from API and update local storage`() =
runTest {
// GIVEN
coEvery { tangemTechApi.getWalletById(testWalletId.stringValue) } returns ApiResponse.Success(
testWalletResponse,
)
coEvery { preferencesDataStore.updateData(any()) } returns mockk<Preferences>()
// WHEN
val result = repository.isNotificationsEnabled(testWalletId, force = true)
// THEN
assertThat(result).isTrue()
coVerify(exactly = 1) {
tangemTechApi.getWalletById(testWalletId.stringValue)
}
coVerify(exactly = 0) {
tangemTechApi.setNotificationsEnabled(any(), any())
}
coVerify(exactly = 1) { preferencesDataStore.updateData(any()) }
}
@Test
fun `GIVEN local storage has value WHEN isNotificationsEnabled THEN should return local value`() = runTest {
// GIVEN
val expectedPreferences = """{"${testWalletId.stringValue}":true}"""
val preferences = mockk<Preferences>()
coEvery { preferencesDataStore.data } returns flowOf(preferences)
coEvery { preferences[PreferencesKeys.NOTIFICATIONS_ENABLED_STATES_KEY] } returns expectedPreferences
coEvery { tangemTechApi.getWalletById(any()) } returns ApiResponse.Success(testWalletResponse)
// WHEN
val result = repository.isNotificationsEnabled(testWalletId, force = false)
// THEN
assertThat(result).isTrue()
coVerify(inverse = true) {
tangemTechApi.getWalletById(any())
tangemTechApi.setNotificationsEnabled(any(), any())
}
}
@Test
fun `GIVEN local storage is empty WHEN isNotificationsEnabled THEN should fetch from API and update local storage`() = runTest {
// GIVEN
val preferences = mockk<Preferences>()
coEvery { preferencesDataStore.data } returns flowOf(preferences)
coEvery { preferences[PreferencesKeys.NOTIFICATIONS_ENABLED_STATES_KEY] } returns "{}"
coEvery { tangemTechApi.getWalletById(testWalletId.stringValue) } returns ApiResponse.Success(
testWalletResponse,
)
coEvery { preferencesDataStore.updateData(any()) } returns mockk<Preferences>()
// WHEN
val result = repository.isNotificationsEnabled(testWalletId, force = false)
// THEN
assertThat(result).isTrue()
coVerify(exactly = 1) {
tangemTechApi.getWalletById(testWalletId.stringValue)
}
coVerify(exactly = 0) {
tangemTechApi.setNotificationsEnabled(any(), any())
}
coVerify(exactly = 1) { preferencesDataStore.updateData(any()) }
}
@Test
fun `GIVEN enabled status WHEN setNotificationsEnabled THEN should update API and local storage`() = runTest {
// GIVEN
coEvery {
tangemTechApi.setNotificationsEnabled(
eq(testWalletId.stringValue),
eq(WalletBody(notifyStatus = true)),
)
} returns ApiResponse.Success(Unit)
coEvery { preferencesDataStore.updateData(any()) } returns mockk<Preferences>()
// WHEN
repository.setNotificationsEnabled(testWalletId, isEnabled = true)
// THEN
coVerify(exactly = 1) {
tangemTechApi.setNotificationsEnabled(
eq(testWalletId.stringValue),
eq(WalletBody(notifyStatus = true)),
)
}
coVerify(exactly = 1) { preferencesDataStore.updateData(any()) }
}
@Test
fun `GIVEN disabled status WHEN setNotificationsEnabled THEN should update API and local storage`() = runTest {
// GIVEN
coEvery {
tangemTechApi.setNotificationsEnabled(
eq(testWalletId.stringValue),
eq(WalletBody(notifyStatus = false)),
)
} returns ApiResponse.Success(Unit)
coEvery { preferencesDataStore.updateData(any()) } returns mockk<Preferences>()
// WHEN
repository.setNotificationsEnabled(testWalletId, isEnabled = false)
// THEN
coVerifyOrder {
tangemTechApi.setNotificationsEnabled(
eq(testWalletId.stringValue),
eq(WalletBody(notifyStatus = false)),
)
preferencesDataStore.updateData(any())
}
coVerify(exactly = 1) {
tangemTechApi.setNotificationsEnabled(
eq(testWalletId.stringValue),
eq(WalletBody(notifyStatus = false)),
)
}
coVerify(exactly = 1) { preferencesDataStore.updateData(any()) }
}
}