Updated on 2026-08-14
This commit is contained in:
parent
56bf204cc5
commit
a6d0b50f43
19 changed files with 319 additions and 113 deletions
|
|
@ -6,6 +6,8 @@ import com.tangem.domain.transaction.usecase.ParseSharedAddressUseCase
|
|||
import com.tangem.domain.transaction.usecase.ValidateWalletAddressUseCase
|
||||
import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.delegate.DefaultUserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
|
@ -28,6 +30,17 @@ import javax.inject.Singleton
|
|||
@InstallIn(SingletonComponent::class)
|
||||
internal object WalletsDomainModule {
|
||||
|
||||
@Provides
|
||||
fun providesUserWalletsSyncDelegate(
|
||||
userWalletsListManager: UserWalletsListManager,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): UserWalletsSyncDelegate {
|
||||
return DefaultUserWalletsSyncDelegate(
|
||||
userWalletsListManager = userWalletsListManager,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesGetWalletsUseCase(userWalletsListManager: UserWalletsListManager): GetWalletsUseCase {
|
||||
|
|
@ -102,10 +115,13 @@ internal object WalletsDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun providesRenameWalletUseCase(
|
||||
userWalletsListManager: UserWalletsListManager,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
walletsRepository: WalletsRepository,
|
||||
userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
): RenameWalletUseCase {
|
||||
return RenameWalletUseCase(userWalletsListManager = userWalletsListManager, dispatchers = dispatchers)
|
||||
return RenameWalletUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
userWalletsSyncDelegate = userWalletsSyncDelegate,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -197,4 +213,16 @@ internal object WalletsDomainModule {
|
|||
nftFeatureToggles = nftFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesUpdateRemoteWalletsInfoUseCase(
|
||||
walletsRepository: WalletsRepository,
|
||||
userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
): UpdateRemoteWalletsInfoUseCase {
|
||||
return UpdateRemoteWalletsInfoUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
userWalletsSyncDelegate = userWalletsSyncDelegate,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -172,6 +172,9 @@ interface TangemTechApi {
|
|||
|
||||
@GET("user-wallets/wallets/{wallet_id}")
|
||||
suspend fun getWalletById(@Path("wallet_id") walletId: String): ApiResponse<WalletResponse>
|
||||
|
||||
@GET("user-wallets/wallets/by-app/{app_id}")
|
||||
suspend fun getWallets(@Path("app_id") appId: String): ApiResponse<List<WalletResponse>>
|
||||
// endregion
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import com.tangem.data.notifications.converters.NotificationsEligibleNetworkConv
|
|||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.models.NotificationApplicationCreateBody
|
||||
import com.tangem.datasource.api.tangemTech.models.WalletBody
|
||||
import com.tangem.datasource.api.tangemTech.models.WalletIdBody
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.*
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -23,7 +23,7 @@ internal class DefaultNotificationsRepository @Inject constructor(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : NotificationsRepository {
|
||||
|
||||
override suspend fun createApplicationId(pushToken: String?): String = withContext(dispatchers.io) {
|
||||
override suspend fun createApplicationId(pushToken: String?): ApplicationId = withContext(dispatchers.io) {
|
||||
tangemTechApi.createApplicationId(
|
||||
NotificationApplicationCreateBody(
|
||||
platform = appInfoProvider.platform,
|
||||
|
|
@ -33,15 +33,16 @@ internal class DefaultNotificationsRepository @Inject constructor(
|
|||
timezone = appInfoProvider.timezone,
|
||||
pushToken = pushToken,
|
||||
),
|
||||
).getOrThrow().appId
|
||||
).getOrThrow().appId.let(::ApplicationId)
|
||||
}
|
||||
|
||||
override suspend fun saveApplicationId(appId: String) {
|
||||
appPreferencesStore.store(PreferencesKeys.NOTIFICATIONS_APPLICATION_ID_KEY, appId)
|
||||
override suspend fun saveApplicationId(appId: ApplicationId) {
|
||||
appPreferencesStore.store(PreferencesKeys.NOTIFICATIONS_APPLICATION_ID_KEY, appId.value)
|
||||
}
|
||||
|
||||
override suspend fun getApplicationId(): String? {
|
||||
override suspend fun getApplicationId(): ApplicationId? {
|
||||
return appPreferencesStore.getSyncOrNull(PreferencesKeys.NOTIFICATIONS_APPLICATION_ID_KEY)
|
||||
?.let(::ApplicationId)
|
||||
}
|
||||
|
||||
override suspend fun incrementTronTokenFeeNotificationShowCounter() {
|
||||
|
|
@ -71,21 +72,10 @@ internal class DefaultNotificationsRepository @Inject constructor(
|
|||
).getOrThrow()
|
||||
}
|
||||
|
||||
override suspend fun setWalletName(walletId: String, walletName: String) = withContext(dispatchers.io) {
|
||||
tangemTechApi.updateWallet(
|
||||
walletId,
|
||||
WalletBody(name = walletName),
|
||||
).getOrThrow()
|
||||
}
|
||||
|
||||
override suspend fun getWalletName(walletId: String): String? = withContext(dispatchers.io) {
|
||||
tangemTechApi.getWalletById(walletId).getOrThrow().name
|
||||
}
|
||||
|
||||
override suspend fun sendPushToken(appId: String, pushToken: String) {
|
||||
override suspend fun sendPushToken(appId: ApplicationId, pushToken: String) {
|
||||
withContext(dispatchers.io) {
|
||||
tangemTechApi.updatePushTokenForApplicationId(
|
||||
appId,
|
||||
appId.value,
|
||||
NotificationApplicationCreateBody(
|
||||
pushToken = pushToken,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.squareup.moshi.Moshi
|
|||
import com.tangem.data.notifications.converters.NotificationsEligibleNetworkConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.*
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
|
@ -41,9 +42,9 @@ class DefaultNotificationsRepositoryTest {
|
|||
fun `GIVEN valid push token WHEN createApplicationId THEN returns application id`() = runTest {
|
||||
// GIVEN
|
||||
val pushToken = "test-push-token"
|
||||
val expectedAppId = "test-app-id"
|
||||
val expectedAppId = ApplicationId("test-app-id")
|
||||
val expectedAppIdResponse = NotificationApplicationIdResponse(
|
||||
appId = expectedAppId,
|
||||
appId = expectedAppId.value,
|
||||
)
|
||||
coEvery { appInfoProvider.platform } returns "android"
|
||||
coEvery { appInfoProvider.device } returns "test-device"
|
||||
|
|
@ -76,7 +77,7 @@ class DefaultNotificationsRepositoryTest {
|
|||
@Test
|
||||
fun `GIVEN application id WHEN saveApplicationId THEN stores it in preferences`() = runTest {
|
||||
// GIVEN
|
||||
val appId = "test-app-id"
|
||||
val appId = ApplicationId("test-app-id")
|
||||
val preferences = mockk<Preferences>(relaxed = true)
|
||||
coEvery { preferencesDataStore.updateData(any()) } returns preferences
|
||||
|
||||
|
|
@ -90,10 +91,10 @@ class DefaultNotificationsRepositoryTest {
|
|||
@Test
|
||||
fun `GIVEN stored application id WHEN getApplicationId THEN returns it`() = runTest {
|
||||
// GIVEN
|
||||
val expectedAppId = "test-app-id"
|
||||
val expectedAppId = ApplicationId("test-app-id")
|
||||
val preferences = mockk<Preferences>(relaxed = true)
|
||||
val key = stringPreferencesKey(PreferencesKeys.NOTIFICATIONS_APPLICATION_ID_KEY.name)
|
||||
every { preferences[key] } returns expectedAppId
|
||||
every { preferences[key] } returns expectedAppId.value
|
||||
coEvery { preferencesDataStore.data } returns flowOf(preferences)
|
||||
|
||||
// WHEN
|
||||
|
|
@ -122,56 +123,24 @@ class DefaultNotificationsRepositoryTest {
|
|||
coVerify { tangemTechApi.associateApplicationIdWithWallets(appId, wallets.map { WalletIdBody(it) }) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallet id and name WHEN setWalletName THEN updates wallet name`() = runTest {
|
||||
// GIVEN
|
||||
val walletId = "test-wallet-id"
|
||||
val walletName = "Test Wallet"
|
||||
coEvery {
|
||||
tangemTechApi.updateWallet(
|
||||
walletId,
|
||||
WalletBody(name = walletName),
|
||||
)
|
||||
} returns ApiResponse.Success(Unit)
|
||||
|
||||
// WHEN
|
||||
repository.setWalletName(walletId, walletName)
|
||||
|
||||
// THEN
|
||||
coVerify { tangemTechApi.updateWallet(walletId, WalletBody(name = walletName)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallet id WHEN getWalletName THEN returns wallet name`() = runTest {
|
||||
// GIVEN
|
||||
val walletId = "test-wallet-id"
|
||||
val expectedName = "Test Wallet"
|
||||
coEvery { tangemTechApi.getWalletById(walletId) } returns ApiResponse.Success(
|
||||
WalletResponse(
|
||||
notifyStatus = false,
|
||||
name = expectedName,
|
||||
id = walletId,
|
||||
),
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = repository.getWalletName(walletId)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(expectedName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN application id and push token WHEN sendPushToken THEN updates push token`() = runTest {
|
||||
// GIVEN
|
||||
val appId = "test-app-id"
|
||||
val appId = ApplicationId("test-app-id")
|
||||
val pushToken = "test-push-token"
|
||||
coEvery {
|
||||
tangemTechApi.updatePushTokenForApplicationId(
|
||||
appId,
|
||||
NotificationApplicationCreateBody(pushToken = pushToken),
|
||||
appId.value,
|
||||
NotificationApplicationCreateBody(
|
||||
pushToken = pushToken,
|
||||
platform = null,
|
||||
device = null,
|
||||
systemVersion = null,
|
||||
language = null,
|
||||
timezone = null,
|
||||
),
|
||||
)
|
||||
} returns ApiResponse.Success(appId)
|
||||
} returns ApiResponse.Success(appId.value)
|
||||
|
||||
// WHEN
|
||||
repository.sendPushToken(appId, pushToken)
|
||||
|
|
@ -179,8 +148,15 @@ class DefaultNotificationsRepositoryTest {
|
|||
// THEN
|
||||
coVerify {
|
||||
tangemTechApi.updatePushTokenForApplicationId(
|
||||
appId,
|
||||
NotificationApplicationCreateBody(pushToken = pushToken),
|
||||
appId.value,
|
||||
NotificationApplicationCreateBody(
|
||||
pushToken = pushToken,
|
||||
platform = null,
|
||||
device = null,
|
||||
systemVersion = null,
|
||||
language = null,
|
||||
timezone = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.wallets
|
||||
|
||||
import com.tangem.data.wallets.converters.UserWalletRemoteInfoConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError.HttpException
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
|
|
@ -18,6 +19,7 @@ import com.tangem.datasource.local.preferences.utils.store
|
|||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.wallets.models.SeedPhraseNotificationsStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.utils.WEEK_MILLIS
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -28,6 +30,7 @@ import kotlinx.coroutines.withContext
|
|||
|
||||
typealias SeedPhraseNotificationsStatuses = Map<UserWalletId, SeedPhraseNotificationsStatus>
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
internal class DefaultWalletsRepository(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
|
|
@ -254,6 +257,37 @@ internal class DefaultWalletsRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun setWalletName(walletId: String, walletName: String) = withContext(dispatchers.io) {
|
||||
tangemTechApi.updateWallet(
|
||||
walletId = walletId,
|
||||
body = WalletBody(name = walletName),
|
||||
).getOrThrow()
|
||||
}
|
||||
|
||||
override suspend fun getWalletInfo(walletId: String): UserWalletRemoteInfo = withContext(dispatchers.io) {
|
||||
UserWalletRemoteInfoConverter.convert(
|
||||
value = tangemTechApi.getWalletById(walletId).getOrThrow(),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getWalletsInfo(applicationId: String, updateCache: Boolean): List<UserWalletRemoteInfo> =
|
||||
withContext(dispatchers.io) {
|
||||
tangemTechApi.getWallets(applicationId)
|
||||
.getOrThrow()
|
||||
.map { walletInfo ->
|
||||
val userWallet = UserWalletRemoteInfoConverter.convert(
|
||||
value = walletInfo,
|
||||
)
|
||||
if (updateCache) {
|
||||
setNotificationsEnabledLocally(
|
||||
userWalletId = userWallet.walletId,
|
||||
isEnabled = userWallet.isNotificationsEnabled,
|
||||
)
|
||||
}
|
||||
userWallet
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadAndSaveNotificationsEnabled(userWalletId: UserWalletId): Boolean {
|
||||
val walletResponse = tangemTechApi.getWalletById(walletId = userWalletId.stringValue).getOrThrow()
|
||||
val isEnabled = walletResponse.notifyStatus
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.data.wallets.converters
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.WalletResponse
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal object UserWalletRemoteInfoConverter : Converter<WalletResponse, UserWalletRemoteInfo> {
|
||||
override fun convert(value: WalletResponse): UserWalletRemoteInfo {
|
||||
return UserWalletRemoteInfo(
|
||||
walletId = UserWalletId(value.id),
|
||||
name = value.name.orEmpty(),
|
||||
isNotificationsEnabled = value.notifyStatus,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -173,4 +173,62 @@ class DefaultWalletsRepositoryTest {
|
|||
}
|
||||
coVerify(exactly = 1) { preferencesDataStore.updateData(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN API returns wallets WHEN getWalletsInfo THEN should return converted wallets and update cache if requested`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = "test_app_id"
|
||||
val wallet1Id = "1234567890abcdef"
|
||||
val wallet2Id = "fedcba0987654321"
|
||||
val walletResponses = listOf(
|
||||
WalletResponse(
|
||||
id = wallet1Id,
|
||||
notifyStatus = true,
|
||||
),
|
||||
WalletResponse(
|
||||
id = wallet2Id,
|
||||
notifyStatus = false,
|
||||
),
|
||||
)
|
||||
coEvery { tangemTechApi.getWallets(applicationId) } returns ApiResponse.Success(walletResponses)
|
||||
coEvery { preferencesDataStore.updateData(any()) } returns mockk<Preferences>()
|
||||
|
||||
// WHEN
|
||||
val result = repository.getWalletsInfo(applicationId, updateCache = true)
|
||||
|
||||
// THEN
|
||||
assertThat(result).hasSize(2)
|
||||
assertThat(result[0].walletId.stringValue).isEqualTo(wallet1Id)
|
||||
assertThat(result[0].isNotificationsEnabled).isTrue()
|
||||
assertThat(result[1].walletId.stringValue).isEqualTo(wallet2Id)
|
||||
assertThat(result[1].isNotificationsEnabled).isFalse()
|
||||
|
||||
coVerify(exactly = 1) { tangemTechApi.getWallets(applicationId) }
|
||||
coVerify(exactly = 2) { preferencesDataStore.updateData(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN API returns wallets WHEN getWalletsInfo with updateCache false THEN should return converted wallets without updating cache`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = "test_app_id"
|
||||
val wallet1Id = "1234567890abcdef"
|
||||
val walletResponses = listOf(
|
||||
WalletResponse(
|
||||
id = wallet1Id,
|
||||
notifyStatus = true,
|
||||
),
|
||||
)
|
||||
coEvery { tangemTechApi.getWallets(applicationId) } returns ApiResponse.Success(walletResponses)
|
||||
|
||||
// WHEN
|
||||
val result = repository.getWalletsInfo(applicationId, updateCache = false)
|
||||
|
||||
// THEN
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result[0].walletId.stringValue).isEqualTo(wallet1Id)
|
||||
assertThat(result[0].isNotificationsEnabled).isTrue()
|
||||
|
||||
coVerify(exactly = 1) { tangemTechApi.getWallets(applicationId) }
|
||||
coVerify(exactly = 0) { preferencesDataStore.updateData(any()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package com.tangem.domain.notifications.models
|
||||
|
||||
@JvmInline
|
||||
value class ApplicationId(val value: String)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.domain.notifications
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
|
@ -10,7 +11,7 @@ class GetApplicationIdUseCase(
|
|||
) {
|
||||
private val mutex = Mutex()
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, String> = Either.catch {
|
||||
suspend operator fun invoke(): Either<Throwable, ApplicationId> = Either.catch {
|
||||
val localApplicationId = notificationsRepository.getApplicationId()
|
||||
if (localApplicationId != null) return@catch localApplicationId
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
package com.tangem.domain.notifications.repository
|
||||
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
|
||||
|
||||
interface NotificationsRepository {
|
||||
|
||||
@Throws
|
||||
suspend fun createApplicationId(pushToken: String? = null): String
|
||||
suspend fun createApplicationId(pushToken: String? = null): ApplicationId
|
||||
|
||||
suspend fun saveApplicationId(appId: String)
|
||||
suspend fun saveApplicationId(appId: ApplicationId)
|
||||
|
||||
suspend fun getApplicationId(): String?
|
||||
suspend fun getApplicationId(): ApplicationId?
|
||||
|
||||
suspend fun getTronTokenFeeNotificationShowCounter(): Int
|
||||
|
||||
|
|
@ -19,13 +20,7 @@ interface NotificationsRepository {
|
|||
suspend fun associateApplicationIdWithWallets(appId: String, wallets: List<String>)
|
||||
|
||||
@Throws
|
||||
suspend fun setWalletName(walletId: String, walletName: String)
|
||||
|
||||
@Throws
|
||||
suspend fun getWalletName(walletId: String): String?
|
||||
|
||||
@Throws
|
||||
suspend fun sendPushToken(appId: String, pushToken: String)
|
||||
suspend fun sendPushToken(appId: ApplicationId, pushToken: String)
|
||||
|
||||
@Throws
|
||||
suspend fun getEligibleNetworks(): List<NotificationsEligibleNetwork>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.domain.notifications
|
|||
|
||||
import arrow.core.Either
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
|
@ -20,7 +21,7 @@ class GetApplicationIdUseCaseTest {
|
|||
@Test
|
||||
fun `GIVEN local application ID exists WHEN invoke THEN return local application ID`() = runTest {
|
||||
// GIVEN
|
||||
val expectedApplicationId = "test-app-id"
|
||||
val expectedApplicationId = ApplicationId("test-app-id")
|
||||
coEvery { notificationsRepository.getApplicationId() } returns expectedApplicationId
|
||||
|
||||
// WHEN
|
||||
|
|
@ -39,7 +40,7 @@ class GetApplicationIdUseCaseTest {
|
|||
@Test
|
||||
fun `GIVEN local application ID does not exist WHEN invoke THEN create and save new application ID`() = runTest {
|
||||
// GIVEN
|
||||
val newApplicationId = "new-app-id"
|
||||
val newApplicationId = ApplicationId("new-app-id")
|
||||
coEvery { notificationsRepository.getApplicationId() } returns null
|
||||
coEvery { notificationsRepository.createApplicationId() } returns newApplicationId
|
||||
coEvery { notificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
|
|
@ -81,7 +82,7 @@ class GetApplicationIdUseCaseTest {
|
|||
fun `GIVEN no local application ID WHEN multiple concurrent invokes THEN create only one application ID`() =
|
||||
runTest {
|
||||
// GIVEN
|
||||
val newApplicationId = "new-app-id"
|
||||
val newApplicationId = ApplicationId("new-app-id")
|
||||
var isIdCreated = false
|
||||
|
||||
coEvery { notificationsRepository.getApplicationId() } answers {
|
||||
|
|
@ -115,7 +116,7 @@ class GetApplicationIdUseCaseTest {
|
|||
@Test
|
||||
fun `GIVEN no local application ID WHEN multiple concurrent invokes with delay THEN create only one application ID`() = runTest {
|
||||
// GIVEN
|
||||
val newApplicationId = "new-app-id"
|
||||
val newApplicationId = ApplicationId("new-app-id")
|
||||
var isIdCreated = false
|
||||
|
||||
coEvery { notificationsRepository.getApplicationId() } answers {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.domain.notifications
|
|||
|
||||
import arrow.core.Either
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
import io.mockk.coEvery
|
||||
|
|
@ -33,7 +34,7 @@ class SendPushTokenUseCaseTest {
|
|||
@Test
|
||||
fun `GIVEN valid application ID and token WHEN invoke THEN token is sent successfully`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = "test-app-id"
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val token = "test-token"
|
||||
coEvery { getApplicationIdUseCase() } returns Either.Right(applicationId)
|
||||
coEvery { pushNotificationsTokenProvider.getToken() } returns token
|
||||
|
|
@ -62,7 +63,7 @@ class SendPushTokenUseCaseTest {
|
|||
@Test
|
||||
fun `GIVEN repository throws error WHEN invoke THEN returns error`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = "test-app-id"
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val token = "test-token"
|
||||
val expectedError = RuntimeException("Network error")
|
||||
coEvery { getApplicationIdUseCase() } returns Either.Right(applicationId)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ dependencies {
|
|||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.notifications.models)
|
||||
// endregion
|
||||
|
||||
// region Tangem libraries
|
||||
|
|
@ -37,4 +38,11 @@ dependencies {
|
|||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
// end
|
||||
|
||||
// region Tests
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(deps.test.mockk)
|
||||
// end
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.domain.wallets.models
|
||||
|
||||
class UserWalletRemoteInfo(
|
||||
val walletId: UserWalletId,
|
||||
val name: String,
|
||||
val isNotificationsEnabled: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tangem.domain.wallets.delegate
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensure
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DefaultUserWalletsSyncDelegate(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : UserWalletsSyncDelegate {
|
||||
|
||||
override suspend fun syncWallet(userWalletId: UserWalletId, name: String): Either<UpdateWalletError, UserWallet> {
|
||||
return renameUserWallet(userWalletId, name)
|
||||
}
|
||||
|
||||
override suspend fun syncWallets(list: List<UserWalletRemoteInfo>): Either<UpdateWalletError, Unit> = either {
|
||||
list.forEach { userWallet ->
|
||||
renameUserWallet(userWallet.walletId, userWallet.name).bind()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun renameUserWallet(
|
||||
userWalletId: UserWalletId,
|
||||
name: String,
|
||||
): Either<UpdateWalletError, UserWallet> = withContext(dispatchers.io) {
|
||||
either {
|
||||
val existingNames = userWalletsListManager.userWalletsSync
|
||||
|
||||
ensure(existingNames.none { it.name == name && it.walletId != userWalletId }) {
|
||||
UpdateWalletError.NameAlreadyExists
|
||||
}
|
||||
|
||||
val previousName = existingNames.firstOrNull { it.walletId == userWalletId }?.name.orEmpty()
|
||||
if (previousName == name) {
|
||||
raise(UpdateWalletError.NameAlreadyExists)
|
||||
}
|
||||
|
||||
return@withContext when (
|
||||
val result =
|
||||
userWalletsListManager.update(userWalletId) { it.copy(name = name) }
|
||||
) {
|
||||
is CompletionResult.Failure -> raise(UpdateWalletError.DataError(result.error))
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.domain.wallets.delegate
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
|
||||
interface UserWalletsSyncDelegate {
|
||||
|
||||
suspend fun syncWallet(userWalletId: UserWalletId, name: String): Either<UpdateWalletError, UserWallet>
|
||||
|
||||
suspend fun syncWallets(list: List<UserWalletRemoteInfo>): Either<UpdateWalletError, Unit>
|
||||
}
|
||||
|
|
@ -2,8 +2,10 @@ package com.tangem.domain.wallets.repository
|
|||
|
||||
import com.tangem.domain.wallets.models.SeedPhraseNotificationsStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
interface WalletsRepository {
|
||||
|
||||
suspend fun shouldSaveUserWalletsSync(): Boolean
|
||||
|
|
@ -43,4 +45,13 @@ interface WalletsRepository {
|
|||
|
||||
@Throws
|
||||
suspend fun setNotificationsEnabled(userWalletId: UserWalletId, isEnabled: Boolean)
|
||||
|
||||
@Throws
|
||||
suspend fun setWalletName(walletId: String, walletName: String)
|
||||
|
||||
@Throws
|
||||
suspend fun getWalletInfo(walletId: String): UserWalletRemoteInfo
|
||||
|
||||
@Throws
|
||||
suspend fun getWalletsInfo(applicationId: String, updateCache: Boolean = true): List<UserWalletRemoteInfo>
|
||||
}
|
||||
|
|
@ -2,38 +2,23 @@ package com.tangem.domain.wallets.usecase
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensure
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
||||
/**
|
||||
* Use case for rename user wallet
|
||||
*
|
||||
* @property userWalletsListManager user wallets list manager
|
||||
*/
|
||||
class RenameWalletUseCase(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, name: String): Either<UpdateWalletError, UserWallet> =
|
||||
withContext(dispatchers.io) {
|
||||
either {
|
||||
val existingNames = userWalletsListManager.userWalletsSync
|
||||
|
||||
ensure(existingNames.none { it.name == name && it.walletId != userWalletId }) {
|
||||
UpdateWalletError.NameAlreadyExists
|
||||
}
|
||||
|
||||
when (val result = userWalletsListManager.update(userWalletId) { it.copy(name = name) }) {
|
||||
is CompletionResult.Failure -> raise(UpdateWalletError.DataError(result.error))
|
||||
is CompletionResult.Success -> result.data
|
||||
}
|
||||
either {
|
||||
runCatching {
|
||||
walletsRepository.setWalletName(userWalletId.stringValue, name)
|
||||
}
|
||||
|
||||
userWalletsSyncDelegate.syncWallet(userWalletId, name).bind()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.models.UpdateWalletError
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
||||
class UpdateRemoteWalletsInfoUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(applicationId: ApplicationId): Either<UpdateWalletError, Unit> = either {
|
||||
val walletsInfo = walletsRepository.getWalletsInfo(applicationId.value)
|
||||
userWalletsSyncDelegate.syncWallets(walletsInfo).bind()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue