1
1
package net.mullvad.mullvadvpn.usecase
2
2
3
3
import android.app.Activity
4
+ import arrow.core.Either
5
+ import arrow.core.right
6
+ import arrow.resilience.Schedule
7
+ import arrow.resilience.retryEither
4
8
import kotlinx.coroutines.delay
5
9
import kotlinx.coroutines.flow.Flow
6
10
import kotlinx.coroutines.flow.MutableStateFlow
7
11
import kotlinx.coroutines.flow.asStateFlow
8
12
import kotlinx.coroutines.flow.transform
9
13
import net.mullvad.mullvadvpn.constant.VERIFICATION_BACK_OFF_FACTOR
10
- import net.mullvad.mullvadvpn.constant.VERIFICATION_INITIAL_BACK_OFF_MILLISECONDS
14
+ import net.mullvad.mullvadvpn.constant.VERIFICATION_INITIAL_BACK_OFF_DURATION
11
15
import net.mullvad.mullvadvpn.constant.VERIFICATION_MAX_ATTEMPTS
12
16
import net.mullvad.mullvadvpn.lib.payment.PaymentRepository
13
17
import net.mullvad.mullvadvpn.lib.payment.model.PaymentAvailability
14
18
import net.mullvad.mullvadvpn.lib.payment.model.ProductId
15
19
import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult
20
+ import net.mullvad.mullvadvpn.lib.payment.model.VerificationError
16
21
import net.mullvad.mullvadvpn.lib.payment.model.VerificationResult
17
- import net.mullvad.mullvadvpn.util.retryWithExponentialBackOff
18
22
19
23
interface PaymentUseCase {
20
24
val paymentAvailability: Flow <PaymentAvailability ?>
@@ -26,7 +30,7 @@ interface PaymentUseCase {
26
30
27
31
suspend fun resetPurchaseResult ()
28
32
29
- suspend fun verifyPurchases (onSuccessfulVerification : () -> Unit = {})
33
+ suspend fun verifyPurchases (): Either < VerificationError , VerificationResult >
30
34
}
31
35
32
36
class PlayPaymentUseCase (private val paymentRepository : PaymentRepository ) : PaymentUseCase {
@@ -60,24 +64,19 @@ class PlayPaymentUseCase(private val paymentRepository: PaymentRepository) : Pay
60
64
}
61
65
62
66
@Suppress(" ensure every public functions method is named 'invoke' with operator modifier" )
63
- override suspend fun verifyPurchases (onSuccessfulVerification : () -> Unit ) {
64
- paymentRepository
65
- .verifyPurchases()
66
- .retryWithExponentialBackOff(
67
- maxAttempts = VERIFICATION_MAX_ATTEMPTS ,
68
- initialBackOffDelay = VERIFICATION_INITIAL_BACK_OFF_MILLISECONDS ,
69
- backOffDelayFactor = VERIFICATION_BACK_OFF_FACTOR
70
- ) {
71
- it is VerificationResult .Error
72
- }
73
- .collect {
67
+ override suspend fun verifyPurchases () =
68
+ Schedule .exponential<VerificationError >(
69
+ VERIFICATION_INITIAL_BACK_OFF_DURATION ,
70
+ VERIFICATION_BACK_OFF_FACTOR
71
+ )
72
+ .and (Schedule .recurs(VERIFICATION_MAX_ATTEMPTS .toLong()))
73
+ .retryEither { paymentRepository.verifyPurchases() }
74
+ .onRight {
74
75
if (it == VerificationResult .Success ) {
75
76
// Update the payment availability after a successful verification.
76
77
queryPaymentAvailability()
77
- onSuccessfulVerification()
78
78
}
79
79
}
80
- }
81
80
82
81
private fun PurchaseResult?.shouldDelayLoading () =
83
82
this is PurchaseResult .FetchingProducts || this is PurchaseResult .VerificationStarted
@@ -107,7 +106,5 @@ class EmptyPaymentUseCase : PaymentUseCase {
107
106
}
108
107
109
108
@Suppress(" ensure every public functions method is named 'invoke' with operator modifier" )
110
- override suspend fun verifyPurchases (onSuccessfulVerification : () -> Unit ) {
111
- // No op
112
- }
109
+ override suspend fun verifyPurchases () = VerificationResult .NothingToVerify .right()
113
110
}
0 commit comments