Updated on 2026-08-14
This commit is contained in:
parent
14df650f1a
commit
be160483d2
25 changed files with 519 additions and 268 deletions
|
|
@ -2,25 +2,25 @@ package com.tangem.domain.notifications
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.notifications.repository.PushNotificationsRepository
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
class GetApplicationIdUseCase(
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
private val pushNotificationsRepository: PushNotificationsRepository,
|
||||
) {
|
||||
private val mutex = Mutex()
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, ApplicationId> = Either.catch {
|
||||
val localApplicationId = notificationsRepository.getApplicationId()
|
||||
val localApplicationId = pushNotificationsRepository.getApplicationId()
|
||||
if (localApplicationId != null) return@catch localApplicationId
|
||||
|
||||
mutex.withLock {
|
||||
val doubleCheckedId = notificationsRepository.getApplicationId()
|
||||
val doubleCheckedId = pushNotificationsRepository.getApplicationId()
|
||||
if (doubleCheckedId != null) return@withLock doubleCheckedId
|
||||
|
||||
val newApplicationId = notificationsRepository.createApplicationId()
|
||||
notificationsRepository.saveApplicationId(newApplicationId)
|
||||
val newApplicationId = pushNotificationsRepository.createApplicationId()
|
||||
pushNotificationsRepository.saveApplicationId(newApplicationId)
|
||||
newApplicationId
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ package com.tangem.domain.notifications
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.notifications.repository.PushNotificationsRepository
|
||||
|
||||
class GetNetworksAvailableForNotificationsUseCase(
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
private val pushNotificationsRepository: PushNotificationsRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, List<NotificationsEligibleNetwork>> = Either.catch {
|
||||
notificationsRepository.getEligibleNetworks()
|
||||
pushNotificationsRepository.getEligibleNetworks()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,16 @@ package com.tangem.domain.notifications
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.notifications.repository.PushNotificationsRepository
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
|
||||
class SendPushTokenUseCase(
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
private val pushNotificationsRepository: PushNotificationsRepository,
|
||||
private val pushNotificationsTokenProvider: PushNotificationsTokenProvider,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(applicationId: ApplicationId): Either<Throwable, Unit> = Either.catch {
|
||||
val token = pushNotificationsTokenProvider.getToken()
|
||||
notificationsRepository.sendPushToken(applicationId, token)
|
||||
pushNotificationsRepository.sendPushToken(applicationId, token)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.domain.notifications
|
||||
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
|
||||
class SetShouldShowNotificationUseCase(
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(key: String, value: Boolean) {
|
||||
notificationsRepository.setShouldShowNotifications(key, value)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.domain.notifications
|
||||
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
|
||||
class ShouldShowNotificationUseCase(
|
||||
private val notificationsRepository: NotificationsRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(key: String): Boolean {
|
||||
return notificationsRepository.shouldShowNotification(key)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,40 @@
|
|||
package com.tangem.domain.notifications.repository
|
||||
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
|
||||
|
||||
/**
|
||||
* Repository interface for managing local notification logic and state.
|
||||
*
|
||||
* This interface provides methods to check and update whether specific notifications should be shown,
|
||||
* as well as to track the display count for certain notifications (e.g., Tron token fee).
|
||||
*
|
||||
* Note: This repository is responsible only for the local logic and state (such as preferences and counters)
|
||||
* regarding notifications. It does **not** directly show or hide notifications to the user.
|
||||
* The actual display and hiding of notifications in the UI is handled by [NotificationsUM],
|
||||
* which uses this repository to determine the appropriate behavior.
|
||||
*/
|
||||
interface NotificationsRepository {
|
||||
|
||||
@Throws
|
||||
suspend fun createApplicationId(pushToken: String? = null): ApplicationId
|
||||
/**
|
||||
* Checks whether a notification with the given [key] should be shown to the user.
|
||||
* @param key The unique identifier for the notification.
|
||||
* @return true if the notification should be shown, false otherwise.
|
||||
*/
|
||||
suspend fun shouldShowNotification(key: String): Boolean
|
||||
|
||||
suspend fun saveApplicationId(appId: ApplicationId)
|
||||
|
||||
suspend fun getApplicationId(): ApplicationId?
|
||||
/**
|
||||
* Sets whether a notification with the given [key] should be shown to the user.
|
||||
* @param key The unique identifier for the notification.
|
||||
* @param value true if the notification should be shown, false otherwise.
|
||||
*/
|
||||
suspend fun setShouldShowNotifications(key: String, value: Boolean)
|
||||
|
||||
/**
|
||||
* Gets the number of times the Tron token fee notification has been shown.
|
||||
* @return The current show counter for the Tron token fee notification.
|
||||
*/
|
||||
suspend fun getTronTokenFeeNotificationShowCounter(): Int
|
||||
|
||||
/**
|
||||
* Increments the counter tracking how many times the Tron token fee notification has been shown.
|
||||
*/
|
||||
suspend fun incrementTronTokenFeeNotificationShowCounter()
|
||||
|
||||
@Throws
|
||||
suspend fun sendPushToken(appId: ApplicationId, pushToken: String)
|
||||
|
||||
@Throws
|
||||
suspend fun getEligibleNetworks(): List<NotificationsEligibleNetwork>
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.domain.notifications.repository
|
||||
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
|
||||
|
||||
interface PushNotificationsRepository {
|
||||
|
||||
@Throws
|
||||
suspend fun createApplicationId(pushToken: String? = null): ApplicationId
|
||||
|
||||
suspend fun saveApplicationId(appId: ApplicationId)
|
||||
|
||||
suspend fun getApplicationId(): ApplicationId?
|
||||
|
||||
@Throws
|
||||
suspend fun sendPushToken(appId: ApplicationId, pushToken: String)
|
||||
|
||||
@Throws
|
||||
suspend fun getEligibleNetworks(): List<NotificationsEligibleNetwork>
|
||||
}
|
||||
|
|
@ -3,7 +3,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.domain.notifications.repository.PushNotificationsRepository
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.coVerifyOrder
|
||||
|
|
@ -15,14 +15,14 @@ import java.net.SocketTimeoutException
|
|||
|
||||
class GetApplicationIdUseCaseTest {
|
||||
|
||||
private val notificationsRepository: NotificationsRepository = mockk()
|
||||
private val useCase = GetApplicationIdUseCase(notificationsRepository)
|
||||
private val pushNotificationsRepository: PushNotificationsRepository = mockk()
|
||||
private val useCase = GetApplicationIdUseCase(pushNotificationsRepository)
|
||||
|
||||
@Test
|
||||
fun `GIVEN local application ID exists WHEN invoke THEN return local application ID`() = runTest {
|
||||
// GIVEN
|
||||
val expectedApplicationId = ApplicationId("test-app-id")
|
||||
coEvery { notificationsRepository.getApplicationId() } returns expectedApplicationId
|
||||
coEvery { pushNotificationsRepository.getApplicationId() } returns expectedApplicationId
|
||||
|
||||
// WHEN
|
||||
val result = useCase()
|
||||
|
|
@ -30,10 +30,10 @@ class GetApplicationIdUseCaseTest {
|
|||
// THEN
|
||||
assertThat(result).isInstanceOf(Either.Right::class.java)
|
||||
assertThat((result as Either.Right).value).isEqualTo(expectedApplicationId)
|
||||
coVerify(exactly = 1) { notificationsRepository.getApplicationId() }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.getApplicationId() }
|
||||
coVerify(inverse = true) {
|
||||
notificationsRepository.createApplicationId()
|
||||
notificationsRepository.saveApplicationId(any())
|
||||
pushNotificationsRepository.createApplicationId()
|
||||
pushNotificationsRepository.saveApplicationId(any())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,9 +41,9 @@ class GetApplicationIdUseCaseTest {
|
|||
fun `GIVEN local application ID does not exist WHEN invoke THEN create and save new application ID`() = runTest {
|
||||
// GIVEN
|
||||
val newApplicationId = ApplicationId("new-app-id")
|
||||
coEvery { notificationsRepository.getApplicationId() } returns null
|
||||
coEvery { notificationsRepository.createApplicationId() } returns newApplicationId
|
||||
coEvery { notificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
coEvery { pushNotificationsRepository.getApplicationId() } returns null
|
||||
coEvery { pushNotificationsRepository.createApplicationId() } returns newApplicationId
|
||||
coEvery { pushNotificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
|
||||
// WHEN
|
||||
val result = useCase()
|
||||
|
|
@ -52,10 +52,10 @@ class GetApplicationIdUseCaseTest {
|
|||
assertThat(result).isInstanceOf(Either.Right::class.java)
|
||||
assertThat((result as Either.Right).value).isEqualTo(newApplicationId)
|
||||
coVerifyOrder {
|
||||
notificationsRepository.getApplicationId()
|
||||
notificationsRepository.getApplicationId()
|
||||
notificationsRepository.createApplicationId()
|
||||
notificationsRepository.saveApplicationId(newApplicationId)
|
||||
pushNotificationsRepository.getApplicationId()
|
||||
pushNotificationsRepository.getApplicationId()
|
||||
pushNotificationsRepository.createApplicationId()
|
||||
pushNotificationsRepository.saveApplicationId(newApplicationId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ class GetApplicationIdUseCaseTest {
|
|||
fun `GIVEN repository throws exception WHEN invoke THEN return Either Left with error`() = runTest {
|
||||
// GIVEN
|
||||
val expectedError = SocketTimeoutException("Test error")
|
||||
coEvery { notificationsRepository.getApplicationId() } throws expectedError
|
||||
coEvery { pushNotificationsRepository.getApplicationId() } throws expectedError
|
||||
|
||||
// WHEN
|
||||
val result = useCase()
|
||||
|
|
@ -71,10 +71,10 @@ class GetApplicationIdUseCaseTest {
|
|||
// THEN
|
||||
assertThat(result).isInstanceOf(Either.Left::class.java)
|
||||
assertThat((result as Either.Left).value).isEqualTo(expectedError)
|
||||
coVerify(exactly = 1) { notificationsRepository.getApplicationId() }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.getApplicationId() }
|
||||
coVerify(inverse = true) {
|
||||
notificationsRepository.createApplicationId()
|
||||
notificationsRepository.saveApplicationId(any())
|
||||
pushNotificationsRepository.createApplicationId()
|
||||
pushNotificationsRepository.saveApplicationId(any())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -85,14 +85,14 @@ class GetApplicationIdUseCaseTest {
|
|||
val newApplicationId = ApplicationId("new-app-id")
|
||||
var isIdCreated = false
|
||||
|
||||
coEvery { notificationsRepository.getApplicationId() } answers {
|
||||
coEvery { pushNotificationsRepository.getApplicationId() } answers {
|
||||
if (!isIdCreated) null else newApplicationId
|
||||
}
|
||||
coEvery { notificationsRepository.createApplicationId() } answers {
|
||||
coEvery { pushNotificationsRepository.createApplicationId() } answers {
|
||||
isIdCreated = true
|
||||
newApplicationId
|
||||
}
|
||||
coEvery { notificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
coEvery { pushNotificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
|
||||
// WHEN
|
||||
val results = coroutineScope {
|
||||
|
|
@ -108,9 +108,9 @@ class GetApplicationIdUseCaseTest {
|
|||
assertThat(result).isInstanceOf(Either.Right::class.java)
|
||||
assertThat((result as Either.Right).value).isEqualTo(newApplicationId)
|
||||
}
|
||||
coVerify(exactly = PARALLEL_COUNT + 1) { notificationsRepository.getApplicationId() }
|
||||
coVerify(exactly = 1) { notificationsRepository.createApplicationId() }
|
||||
coVerify(exactly = 1) { notificationsRepository.saveApplicationId(newApplicationId) }
|
||||
coVerify(exactly = PARALLEL_COUNT + 1) { pushNotificationsRepository.getApplicationId() }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.createApplicationId() }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.saveApplicationId(newApplicationId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -119,14 +119,14 @@ class GetApplicationIdUseCaseTest {
|
|||
val newApplicationId = ApplicationId("new-app-id")
|
||||
var isIdCreated = false
|
||||
|
||||
coEvery { notificationsRepository.getApplicationId() } answers {
|
||||
coEvery { pushNotificationsRepository.getApplicationId() } answers {
|
||||
if (!isIdCreated) null else newApplicationId
|
||||
}
|
||||
coEvery { notificationsRepository.createApplicationId() } answers {
|
||||
coEvery { pushNotificationsRepository.createApplicationId() } answers {
|
||||
isIdCreated = true
|
||||
newApplicationId
|
||||
}
|
||||
coEvery { notificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
coEvery { pushNotificationsRepository.saveApplicationId(newApplicationId) } returns Unit
|
||||
|
||||
// WHEN
|
||||
val results = coroutineScope {
|
||||
|
|
@ -143,9 +143,9 @@ class GetApplicationIdUseCaseTest {
|
|||
assertThat(result).isInstanceOf(Either.Right::class.java)
|
||||
assertThat((result as Either.Right).value).isEqualTo(newApplicationId)
|
||||
}
|
||||
coVerify(exactly = PARALLEL_COUNT + 1) { notificationsRepository.getApplicationId() }
|
||||
coVerify(exactly = 1) { notificationsRepository.createApplicationId() }
|
||||
coVerify(exactly = 1) { notificationsRepository.saveApplicationId(newApplicationId) }
|
||||
coVerify(exactly = PARALLEL_COUNT + 1) { pushNotificationsRepository.getApplicationId() }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.createApplicationId() }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.saveApplicationId(newApplicationId) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,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.domain.notifications.repository.PushNotificationsRepository
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
|
@ -14,16 +14,16 @@ import org.junit.Test
|
|||
|
||||
class SendPushTokenUseCaseTest {
|
||||
|
||||
private lateinit var notificationsRepository: NotificationsRepository
|
||||
private lateinit var pushNotificationsRepository: PushNotificationsRepository
|
||||
private lateinit var pushNotificationsTokenProvider: PushNotificationsTokenProvider
|
||||
private lateinit var sendPushTokenUseCase: SendPushTokenUseCase
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
notificationsRepository = mockk()
|
||||
pushNotificationsRepository = mockk()
|
||||
pushNotificationsTokenProvider = mockk()
|
||||
sendPushTokenUseCase = SendPushTokenUseCase(
|
||||
notificationsRepository = notificationsRepository,
|
||||
pushNotificationsRepository = pushNotificationsRepository,
|
||||
pushNotificationsTokenProvider = pushNotificationsTokenProvider,
|
||||
)
|
||||
}
|
||||
|
|
@ -34,14 +34,14 @@ class SendPushTokenUseCaseTest {
|
|||
val applicationId = ApplicationId("test-app-id")
|
||||
val token = "test-token"
|
||||
coEvery { pushNotificationsTokenProvider.getToken() } returns token
|
||||
coEvery { notificationsRepository.sendPushToken(applicationId, token) } returns Unit
|
||||
coEvery { pushNotificationsRepository.sendPushToken(applicationId, token) } returns Unit
|
||||
|
||||
// WHEN
|
||||
val result = sendPushTokenUseCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(Either.Right(Unit))
|
||||
coVerify(exactly = 1) { notificationsRepository.sendPushToken(applicationId, token) }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.sendPushToken(applicationId, token) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -51,13 +51,13 @@ class SendPushTokenUseCaseTest {
|
|||
val token = "test-token"
|
||||
val expectedError = RuntimeException("Network error")
|
||||
coEvery { pushNotificationsTokenProvider.getToken() } returns token
|
||||
coEvery { notificationsRepository.sendPushToken(applicationId, token) } throws expectedError
|
||||
coEvery { pushNotificationsRepository.sendPushToken(applicationId, token) } throws expectedError
|
||||
|
||||
// WHEN
|
||||
val result = sendPushTokenUseCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result).isEqualTo(Either.Left(expectedError))
|
||||
coVerify(exactly = 1) { notificationsRepository.sendPushToken(applicationId, token) }
|
||||
coVerify(exactly = 1) { pushNotificationsRepository.sendPushToken(applicationId, token) }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue