feat: Added CreateAccountNeeded handling.
This commit is contained in:
parent
b2f50c3cc0
commit
fd105f362e
|
@ -5,7 +5,7 @@ public class hilt_aggregated_deps/_me_proton_core_accountmanager_data_RefreshUse
|
|||
public final class me/proton/core/accountmanager/data/AccountManagerImpl : me/proton/core/accountmanager/domain/AccountManager, me/proton/core/accountmanager/domain/AccountWorkflowHandler {
|
||||
public fun <init> (Lme/proton/core/domain/entity/Product;Lme/proton/core/account/domain/repository/AccountRepository;Lme/proton/core/auth/domain/repository/AuthRepository;Lme/proton/core/user/domain/UserManager;Lme/proton/core/network/domain/session/SessionListener;)V
|
||||
public fun addAccount (Lme/proton/core/account/domain/entity/Account;Lme/proton/core/network/domain/session/Session;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun disableAccount (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun disableAccount (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun getAccount (Lme/proton/core/domain/entity/UserId;)Lkotlinx/coroutines/flow/Flow;
|
||||
public fun getAccounts ()Lkotlinx/coroutines/flow/Flow;
|
||||
public fun getPreviousPrimaryUserId (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
|
|
@ -28,7 +28,7 @@ protonBuild {
|
|||
}
|
||||
|
||||
protonCoverage {
|
||||
branchCoveragePercentage.set(45)
|
||||
branchCoveragePercentage.set(43)
|
||||
lineCoveragePercentage.set(79)
|
||||
}
|
||||
|
||||
|
|
|
@ -74,14 +74,14 @@ class AccountManagerImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun disableAccount(account: Account) {
|
||||
private suspend fun disableAccount(account: Account, keepSession: Boolean) {
|
||||
accountRepository.updateAccountState(account.userId, Disabled)
|
||||
account.sessionId?.let { removeSession(it) }
|
||||
account.sessionId?.takeUnless { keepSession }?.let { removeSession(it) }
|
||||
userManager.lock(account.userId)
|
||||
}
|
||||
|
||||
private suspend fun disableAccount(sessionId: SessionId) {
|
||||
accountRepository.getAccountOrNull(sessionId)?.let { disableAccount(it) }
|
||||
private suspend fun disableAccount(sessionId: SessionId, keepSession: Boolean) {
|
||||
accountRepository.getAccountOrNull(sessionId)?.let { disableAccount(it, keepSession) }
|
||||
}
|
||||
|
||||
private suspend fun clearSessionDetails(userId: UserId) {
|
||||
|
@ -100,8 +100,8 @@ class AccountManagerImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun disableAccount(userId: UserId) {
|
||||
accountRepository.getAccountOrNull(userId)?.let { disableAccount(it) }
|
||||
override suspend fun disableAccount(userId: UserId, keepSession: Boolean) {
|
||||
accountRepository.getAccountOrNull(userId)?.let { disableAccount(it, keepSession) }
|
||||
}
|
||||
|
||||
override fun getAccount(userId: UserId): Flow<Account?> =
|
||||
|
@ -160,7 +160,7 @@ class AccountManagerImpl @Inject constructor(
|
|||
|
||||
override suspend fun handleSecondFactorFailed(sessionId: SessionId) {
|
||||
accountRepository.updateSessionState(sessionId, SessionState.SecondFactorFailed)
|
||||
disableAccount(sessionId)
|
||||
disableAccount(sessionId, keepSession = false)
|
||||
}
|
||||
|
||||
override suspend fun handleCreateAddressNeeded(userId: UserId) {
|
||||
|
@ -181,6 +181,7 @@ class AccountManagerImpl @Inject constructor(
|
|||
|
||||
override suspend fun handleCreateAccountSuccess(userId: UserId) {
|
||||
accountRepository.updateAccountState(userId, CreateAccountSuccess)
|
||||
disableAccount(userId, keepSession = true)
|
||||
}
|
||||
|
||||
override suspend fun handleCreateAccountFailed(userId: UserId) {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
public abstract class me/proton/core/accountmanager/domain/AccountManager {
|
||||
public fun <init> (Lme/proton/core/domain/entity/Product;)V
|
||||
public abstract fun addAccount (Lme/proton/core/account/domain/entity/Account;Lme/proton/core/network/domain/session/Session;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun disableAccount (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun disableAccount (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static synthetic fun disableAccount$default (Lme/proton/core/accountmanager/domain/AccountManager;Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
|
||||
public abstract fun getAccount (Lme/proton/core/domain/entity/UserId;)Lkotlinx/coroutines/flow/Flow;
|
||||
public abstract fun getAccounts ()Lkotlinx/coroutines/flow/Flow;
|
||||
public abstract fun getPreviousPrimaryUserId (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
|
|
@ -58,7 +58,7 @@ abstract class AccountManager(
|
|||
*
|
||||
* Note: The [Account.state] will be set to [AccountState.Disabled].
|
||||
*/
|
||||
abstract suspend fun disableAccount(userId: UserId)
|
||||
abstract suspend fun disableAccount(userId: UserId, keepSession: Boolean = false)
|
||||
|
||||
/**
|
||||
* Flow of persisted [Account] on this device, by userId.
|
||||
|
|
|
@ -14,6 +14,10 @@ public final class me/proton/core/accountmanager/presentation/AccountManagerObse
|
|||
public final class me/proton/core/accountmanager/presentation/AccountManagerObserverKt {
|
||||
public static final fun observe (Lme/proton/core/accountmanager/domain/AccountManager;Landroidx/lifecycle/Lifecycle;Landroidx/lifecycle/Lifecycle$State;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static synthetic fun observe$default (Lme/proton/core/accountmanager/domain/AccountManager;Landroidx/lifecycle/Lifecycle;Landroidx/lifecycle/Lifecycle$State;ILjava/lang/Object;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static final fun onAccountCreateAccountFailed (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static synthetic fun onAccountCreateAccountFailed$default (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static final fun onAccountCreateAccountNeeded (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static synthetic fun onAccountCreateAccountNeeded$default (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static final fun onAccountCreateAddressFailed (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static synthetic fun onAccountCreateAddressFailed$default (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
public static final fun onAccountCreateAddressNeeded (Lme/proton/core/accountmanager/presentation/AccountManagerObserver;ZLkotlin/jvm/functions/Function2;)Lme/proton/core/accountmanager/presentation/AccountManagerObserver;
|
||||
|
|
|
@ -98,6 +98,22 @@ fun AccountManagerObserver.onAccountCreateAddressFailed(
|
|||
return this
|
||||
}
|
||||
|
||||
fun AccountManagerObserver.onAccountCreateAccountNeeded(
|
||||
initialState: Boolean = true,
|
||||
block: suspend (Account) -> Unit
|
||||
): AccountManagerObserver {
|
||||
addAccountStateListener(AccountState.CreateAccountNeeded, initialState, block)
|
||||
return this
|
||||
}
|
||||
|
||||
fun AccountManagerObserver.onAccountCreateAccountFailed(
|
||||
initialState: Boolean = true,
|
||||
block: suspend (Account) -> Unit
|
||||
): AccountManagerObserver {
|
||||
addAccountStateListener(AccountState.CreateAccountFailed, initialState, block)
|
||||
return this
|
||||
}
|
||||
|
||||
fun AccountManagerObserver.onAccountReady(
|
||||
initialState: Boolean = true,
|
||||
block: suspend (Account) -> Unit
|
||||
|
|
|
@ -27,7 +27,7 @@ protonBuild {
|
|||
}
|
||||
|
||||
protonCoverage {
|
||||
branchCoveragePercentage.set(64)
|
||||
branchCoveragePercentage.set(63)
|
||||
lineCoveragePercentage.set(92)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
public final class me/proton/core/auth/domain/LogTag {
|
||||
public static final field INSTANCE Lme/proton/core/auth/domain/LogTag;
|
||||
public static final field INVALID_SRP_PROOF Ljava/lang/String;
|
||||
public static final field PERFORM_SUBSCRIBE Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract class me/proton/core/auth/domain/entity/AuthInfo {
|
||||
|
@ -317,7 +318,7 @@ public final class me/proton/core/auth/domain/usecase/PerformSecondFactor {
|
|||
}
|
||||
|
||||
public final class me/proton/core/auth/domain/usecase/PostLoginAccountSetup {
|
||||
public fun <init> (Lme/proton/core/accountmanager/domain/AccountWorkflowHandler;Lme/proton/core/plan/domain/usecase/PerformSubscribe;Lme/proton/core/auth/domain/usecase/SetupAccountCheck;Lme/proton/core/auth/domain/usecase/SetupExternalAddressKeys;Lme/proton/core/auth/domain/usecase/SetupInternalAddress;Lme/proton/core/auth/domain/usecase/SetupPrimaryKeys;Lme/proton/core/auth/domain/usecase/UnlockUserPrimaryKey;Lme/proton/core/auth/domain/usecase/PostLoginAccountSetup$UserCheck;Lme/proton/core/user/domain/UserManager;Lme/proton/core/accountmanager/domain/SessionManager;)V
|
||||
public fun <init> (Lme/proton/core/accountmanager/domain/AccountWorkflowHandler;Lme/proton/core/plan/domain/usecase/PerformSubscribe;Lme/proton/core/payment/domain/repository/PurchaseRepository;Lme/proton/core/plan/domain/repository/PlansRepository;Lme/proton/core/auth/domain/usecase/SetupAccountCheck;Lme/proton/core/auth/domain/usecase/SetupExternalAddressKeys;Lme/proton/core/auth/domain/usecase/SetupInternalAddress;Lme/proton/core/auth/domain/usecase/SetupPrimaryKeys;Lme/proton/core/auth/domain/usecase/UnlockUserPrimaryKey;Lme/proton/core/auth/domain/usecase/PostLoginAccountSetup$UserCheck;Lme/proton/core/user/domain/UserManager;Lme/proton/core/accountmanager/domain/SessionManager;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Ljava/lang/String;Lme/proton/core/account/domain/entity/AccountType;ZZZLkotlin/jvm/functions/Function1;Lme/proton/core/auth/domain/entity/BillingDetails;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public static synthetic fun invoke$default (Lme/proton/core/auth/domain/usecase/PostLoginAccountSetup;Lme/proton/core/domain/entity/UserId;Ljava/lang/String;Lme/proton/core/account/domain/entity/AccountType;ZZZLkotlin/jvm/functions/Function1;Lme/proton/core/auth/domain/entity/BillingDetails;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
|
||||
}
|
||||
|
@ -553,6 +554,11 @@ public final class me/proton/core/auth/domain/usecase/signup/PerformCreateUser {
|
|||
public final fun invoke (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lme/proton/core/user/domain/entity/CreateUserType;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/auth/domain/usecase/signup/SetCreateAccountSuccess {
|
||||
public fun <init> (Lme/proton/core/accountmanager/domain/AccountManager;Lme/proton/core/accountmanager/domain/AccountWorkflowHandler;)V
|
||||
public final fun invoke (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/auth/domain/usecase/signup/SignupChallengeConfig : me/proton/core/challenge/domain/ChallengeConfig {
|
||||
public static final field Companion Lme/proton/core/auth/domain/usecase/signup/SignupChallengeConfig$Companion;
|
||||
public static final field SIGN_UP_FRAME_RECOVERY Ljava/lang/String;
|
||||
|
|
|
@ -30,7 +30,7 @@ protonBuild {
|
|||
|
||||
protonCoverage {
|
||||
branchCoveragePercentage.set(62)
|
||||
lineCoveragePercentage.set(86)
|
||||
lineCoveragePercentage.set(85)
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
|
|
@ -20,4 +20,5 @@ package me.proton.core.auth.domain
|
|||
|
||||
object LogTag {
|
||||
const val INVALID_SRP_PROOF = "core.auth.domain.srp.invalid.server.proof"
|
||||
const val PERFORM_SUBSCRIBE = "core.auth.domain.perform.subscribe"
|
||||
}
|
||||
|
|
|
@ -19,14 +19,24 @@
|
|||
package me.proton.core.auth.domain.usecase
|
||||
|
||||
import me.proton.core.account.domain.entity.AccountType
|
||||
import me.proton.core.accountmanager.domain.SessionManager
|
||||
import me.proton.core.accountmanager.domain.AccountWorkflowHandler
|
||||
import me.proton.core.accountmanager.domain.SessionManager
|
||||
import me.proton.core.auth.domain.LogTag
|
||||
import me.proton.core.auth.domain.entity.BillingDetails
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.payment.domain.MAX_PLAN_QUANTITY
|
||||
import me.proton.core.payment.domain.entity.PaymentTokenEntity
|
||||
import me.proton.core.payment.domain.entity.PurchaseState
|
||||
import me.proton.core.payment.domain.entity.SubscriptionCycle
|
||||
import me.proton.core.payment.domain.extension.getPurchaseOrNull
|
||||
import me.proton.core.payment.domain.repository.PurchaseRepository
|
||||
import me.proton.core.plan.domain.entity.SubscriptionManagement
|
||||
import me.proton.core.plan.domain.repository.PlansRepository
|
||||
import me.proton.core.plan.domain.usecase.PerformSubscribe
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.entity.User
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -35,6 +45,8 @@ import javax.inject.Inject
|
|||
class PostLoginAccountSetup @Inject constructor(
|
||||
private val accountWorkflow: AccountWorkflowHandler,
|
||||
private val performSubscribe: PerformSubscribe,
|
||||
private val purchaseRepository: PurchaseRepository,
|
||||
private val planRepository: PlansRepository,
|
||||
private val setupAccountCheck: SetupAccountCheck,
|
||||
private val setupExternalAddressKeys: SetupExternalAddressKeys,
|
||||
private val setupInternalAddress: SetupInternalAddress,
|
||||
|
@ -83,21 +95,10 @@ class PostLoginAccountSetup @Inject constructor(
|
|||
billingDetails: BillingDetails? = null,
|
||||
internalAddressDomain: String? = null
|
||||
): Result {
|
||||
// Subscribe to any pending subscription/billing.
|
||||
// TODO: Add If any Purchase in Purchased state for this userId -> use it.
|
||||
if (billingDetails != null) {
|
||||
runCatching {
|
||||
performSubscribe(
|
||||
userId = userId,
|
||||
amount = billingDetails.amount,
|
||||
currency = billingDetails.currency,
|
||||
cycle = billingDetails.cycle,
|
||||
planNames = listOf(billingDetails.planName),
|
||||
paymentToken = billingDetails.token,
|
||||
subscriptionManagement = billingDetails.subscriptionManagement
|
||||
)
|
||||
}
|
||||
}
|
||||
// Flows not using PurchaseStateHandler pass billingDetails.
|
||||
subscribeAnyPendingBilling(billingDetails, userId)
|
||||
// Flows using PurchaseStateHandler drop a Purchase off.
|
||||
subscribeAnyPendingPurchase(userId)
|
||||
|
||||
// If SecondFactorNeeded, we cannot proceed without.
|
||||
if (isSecondFactorNeeded) {
|
||||
|
@ -158,6 +159,51 @@ class PostLoginAccountSetup @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun subscribeAnyPendingBilling(
|
||||
billingDetails: BillingDetails?,
|
||||
userId: UserId
|
||||
) {
|
||||
if (billingDetails != null) runCatching {
|
||||
performSubscribe(
|
||||
userId = userId,
|
||||
amount = billingDetails.amount,
|
||||
currency = billingDetails.currency,
|
||||
cycle = billingDetails.cycle,
|
||||
planNames = listOf(billingDetails.planName),
|
||||
paymentToken = billingDetails.token,
|
||||
subscriptionManagement = billingDetails.subscriptionManagement
|
||||
)
|
||||
}.onFailure {
|
||||
CoreLogger.e(LogTag.PERFORM_SUBSCRIBE, it)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun subscribeAnyPendingPurchase(userId: UserId) {
|
||||
val purchase = purchaseRepository.getPurchaseOrNull(PurchaseState.Purchased)
|
||||
if (purchase != null) runCatching {
|
||||
planRepository.createOrUpdateSubscription(
|
||||
sessionUserId = userId,
|
||||
amount = purchase.paymentAmount,
|
||||
currency = purchase.paymentCurrency,
|
||||
payment = PaymentTokenEntity(requireNotNull(purchase.paymentToken)),
|
||||
codes = null,
|
||||
plans = listOf(purchase.planName).associateWith { MAX_PLAN_QUANTITY },
|
||||
cycle = SubscriptionCycle.map[purchase.planCycle] ?: SubscriptionCycle.OTHER,
|
||||
subscriptionManagement = SubscriptionManagement.GOOGLE_MANAGED
|
||||
)
|
||||
}.onSuccess {
|
||||
purchaseRepository.upsertPurchase(purchase.copy(purchaseState = PurchaseState.Subscribed))
|
||||
}.onFailure {
|
||||
CoreLogger.e(LogTag.PERFORM_SUBSCRIBE, it)
|
||||
purchaseRepository.upsertPurchase(
|
||||
purchase.copy(
|
||||
purchaseFailure = it.localizedMessage,
|
||||
purchaseState = PurchaseState.Failed
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun unlockUserPrimaryKey(
|
||||
userId: UserId,
|
||||
password: EncryptedString,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package me.proton.core.auth.domain.usecase.signup
|
||||
|
||||
import kotlinx.coroutines.flow.first
|
||||
import me.proton.core.account.domain.entity.AccountState
|
||||
import me.proton.core.accountmanager.domain.AccountManager
|
||||
import me.proton.core.accountmanager.domain.AccountWorkflowHandler
|
||||
import me.proton.core.accountmanager.domain.getAccounts
|
||||
import me.proton.core.util.kotlin.annotation.ExcludeFromCoverage
|
||||
import javax.inject.Inject
|
||||
|
||||
@ExcludeFromCoverage
|
||||
class SetCreateAccountSuccess @Inject constructor(
|
||||
private val accountManager: AccountManager,
|
||||
private val accountWorkflowHandler: AccountWorkflowHandler
|
||||
) {
|
||||
suspend operator fun invoke() {
|
||||
accountManager.getAccounts(AccountState.CreateAccountNeeded).first().forEach {
|
||||
accountWorkflowHandler.handleCreateAccountSuccess(it.userId)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,16 +26,23 @@ import io.mockk.mockk
|
|||
import io.mockk.slot
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import me.proton.core.account.domain.entity.AccountType
|
||||
import me.proton.core.accountmanager.domain.SessionManager
|
||||
import me.proton.core.accountmanager.domain.AccountWorkflowHandler
|
||||
import me.proton.core.accountmanager.domain.SessionManager
|
||||
import me.proton.core.auth.domain.entity.BillingDetails
|
||||
import me.proton.core.auth.domain.entity.SessionInfo
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.network.domain.session.SessionId
|
||||
import me.proton.core.payment.domain.entity.Currency
|
||||
import me.proton.core.payment.domain.entity.PaymentTokenEntity
|
||||
import me.proton.core.payment.domain.entity.ProtonPaymentToken
|
||||
import me.proton.core.payment.domain.entity.Purchase
|
||||
import me.proton.core.payment.domain.entity.PurchaseState
|
||||
import me.proton.core.payment.domain.entity.SubscriptionCycle
|
||||
import me.proton.core.payment.domain.repository.PlanQuantity
|
||||
import me.proton.core.payment.domain.repository.PurchaseRepository
|
||||
import me.proton.core.payment.domain.usecase.PaymentProvider
|
||||
import me.proton.core.plan.domain.entity.SubscriptionManagement
|
||||
import me.proton.core.plan.domain.repository.PlansRepository
|
||||
import me.proton.core.plan.domain.usecase.PerformSubscribe
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.entity.User
|
||||
|
@ -47,6 +54,8 @@ import kotlin.test.assertTrue
|
|||
class PostLoginAccountSetupTest {
|
||||
private lateinit var accountWorkflowHandler: AccountWorkflowHandler
|
||||
private lateinit var performSubscribe: PerformSubscribe
|
||||
private lateinit var purchaseRepository: PurchaseRepository
|
||||
private lateinit var planRepository: PlansRepository
|
||||
private lateinit var setupAccountCheck: SetupAccountCheck
|
||||
private lateinit var setupInternalAddress: SetupInternalAddress
|
||||
private lateinit var setupExternalAddressKeys: SetupExternalAddressKeys
|
||||
|
@ -69,6 +78,7 @@ class PostLoginAccountSetupTest {
|
|||
fun setUp() {
|
||||
accountWorkflowHandler = mockk()
|
||||
performSubscribe = mockk()
|
||||
planRepository = mockk(relaxed = true)
|
||||
setupAccountCheck = mockk()
|
||||
setupExternalAddressKeys = mockk()
|
||||
setupInternalAddress = mockk()
|
||||
|
@ -89,9 +99,15 @@ class PostLoginAccountSetupTest {
|
|||
coEvery { refreshScopes(any()) } returns Unit
|
||||
}
|
||||
|
||||
purchaseRepository = mockk(relaxed = true) {
|
||||
coEvery { getPurchases() } returns emptyList()
|
||||
}
|
||||
|
||||
tested = PostLoginAccountSetup(
|
||||
accountWorkflowHandler,
|
||||
performSubscribe,
|
||||
purchaseRepository,
|
||||
planRepository,
|
||||
setupAccountCheck,
|
||||
setupExternalAddressKeys,
|
||||
setupInternalAddress,
|
||||
|
@ -245,6 +261,74 @@ class PostLoginAccountSetupTest {
|
|||
assertEquals(ProtonPaymentToken("test-token"), paymentToken.captured)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `subscription setup with purchase`() = runTest {
|
||||
val sessionInfo = mockSessionInfo()
|
||||
val pendingUserId = UserId("pendingUserId")
|
||||
val pendingSessionId = SessionId("pendingSessionId")
|
||||
val purchase = Purchase(
|
||||
sessionId = pendingSessionId,
|
||||
planName = "test-plan-name",
|
||||
planCycle = 12,
|
||||
purchaseState = PurchaseState.Purchased,
|
||||
purchaseFailure = null,
|
||||
paymentProvider = PaymentProvider.GoogleInAppPurchase,
|
||||
paymentOrderId = "orderId",
|
||||
paymentToken = ProtonPaymentToken("test-token"),
|
||||
paymentCurrency = Currency.EUR,
|
||||
paymentAmount = 99
|
||||
)
|
||||
coEvery { purchaseRepository.getPurchases() } returns listOf(purchase)
|
||||
coEvery { sessionManager.getUserId(pendingSessionId) } returns pendingUserId
|
||||
|
||||
coJustRun { accountWorkflowHandler.handleAccountReady(any()) }
|
||||
coJustRun { accountWorkflowHandler.handleCreateAccountSuccess(any()) }
|
||||
coEvery { setupAccountCheck.invoke(any(), any(), any(), any()) } returns SetupAccountCheck.Result.NoSetupNeeded
|
||||
coEvery { unlockUserPrimaryKey.invoke(any(), any()) } returns UserManager.UnlockResult.Success
|
||||
|
||||
val result = tested.invoke(
|
||||
sessionInfo.userId,
|
||||
testEncryptedPassword,
|
||||
testAccountType,
|
||||
isSecondFactorNeeded = sessionInfo.isSecondFactorNeeded,
|
||||
isTwoPassModeNeeded = sessionInfo.isTwoPassModeNeeded,
|
||||
temporaryPassword = sessionInfo.temporaryPassword,
|
||||
onSetupSuccess = onSetupSuccess
|
||||
)
|
||||
|
||||
assertEquals(PostLoginAccountSetup.Result.UserUnlocked(testUserId), result)
|
||||
coVerify(exactly = 1) { onSetupSuccess() }
|
||||
|
||||
val userId = slot<UserId>()
|
||||
val amount = slot<Long>()
|
||||
val currency = slot<Currency>()
|
||||
val cycle = slot<SubscriptionCycle>()
|
||||
val plans = slot<PlanQuantity>()
|
||||
val paymentToken = slot<PaymentTokenEntity>()
|
||||
coVerify {
|
||||
planRepository.createOrUpdateSubscription(
|
||||
capture(userId),
|
||||
capture(amount),
|
||||
capture(currency),
|
||||
capture(paymentToken),
|
||||
codes = null,
|
||||
capture(plans),
|
||||
capture(cycle),
|
||||
subscriptionManagement = SubscriptionManagement.GOOGLE_MANAGED
|
||||
)
|
||||
}
|
||||
assertEquals(testUserId, userId.captured)
|
||||
assertEquals(99, amount.captured)
|
||||
assertEquals(Currency.EUR, currency.captured)
|
||||
assertEquals(SubscriptionCycle.YEARLY, cycle.captured)
|
||||
assertEquals(mapOf("test-plan-name" to 1), plans.captured)
|
||||
assertEquals(PaymentTokenEntity(ProtonPaymentToken("test-token")), paymentToken.captured)
|
||||
|
||||
val actualPurchase = slot<Purchase>()
|
||||
coVerify { purchaseRepository.upsertPurchase(capture(actualPurchase)) }
|
||||
assertEquals(PurchaseState.Subscribed, actualPurchase.captured.purchaseState)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `user check error`() = runTest {
|
||||
val setupError = mockk<PostLoginAccountSetup.UserCheckResult.Error>()
|
||||
|
|
|
@ -226,8 +226,8 @@ public final class me/proton/core/auth/presentation/AuthOrchestrator {
|
|||
public final fun startLoginWorkflow (Lme/proton/core/account/domain/entity/AccountType;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public static synthetic fun startLoginWorkflow$default (Lme/proton/core/auth/presentation/AuthOrchestrator;Lme/proton/core/account/domain/entity/AccountType;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)V
|
||||
public final fun startSecondFactorWorkflow (Lme/proton/core/account/domain/entity/Account;)V
|
||||
public final fun startSignupWorkflow (Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)V
|
||||
public static synthetic fun startSignupWorkflow$default (Lme/proton/core/auth/presentation/AuthOrchestrator;Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILjava/lang/Object;)V
|
||||
public final fun startSignupWorkflow (Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)V
|
||||
public static synthetic fun startSignupWorkflow$default (Lme/proton/core/auth/presentation/AuthOrchestrator;Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILjava/lang/Object;)V
|
||||
public final fun startTwoPassModeWorkflow (Lme/proton/core/account/domain/entity/Account;)V
|
||||
public final fun unregister ()V
|
||||
}
|
||||
|
@ -1282,15 +1282,19 @@ public final class me/proton/core/auth/presentation/entity/signup/RecoveryMethod
|
|||
|
||||
public final class me/proton/core/auth/presentation/entity/signup/SignUpInput : android/os/Parcelable {
|
||||
public static final field CREATOR Landroid/os/Parcelable$Creator;
|
||||
public fun <init> (Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)V
|
||||
public synthetic fun <init> (Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun <init> (Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)V
|
||||
public synthetic fun <init> (Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lme/proton/core/account/domain/entity/AccountType;
|
||||
public final fun component2 ()Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;
|
||||
public final fun copy (Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)Lme/proton/core/auth/presentation/entity/signup/SignUpInput;
|
||||
public static synthetic fun copy$default (Lme/proton/core/auth/presentation/entity/signup/SignUpInput;Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILjava/lang/Object;)Lme/proton/core/auth/presentation/entity/signup/SignUpInput;
|
||||
public final fun component2 ()Z
|
||||
public final fun component3 ()Ljava/lang/String;
|
||||
public final fun component4 ()Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;
|
||||
public final fun copy (Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)Lme/proton/core/auth/presentation/entity/signup/SignUpInput;
|
||||
public static synthetic fun copy$default (Lme/proton/core/auth/presentation/entity/signup/SignUpInput;Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILjava/lang/Object;)Lme/proton/core/auth/presentation/entity/signup/SignUpInput;
|
||||
public fun describeContents ()I
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getCancellable ()Z
|
||||
public final fun getCreatableAccountType ()Lme/proton/core/account/domain/entity/AccountType;
|
||||
public final fun getEmail ()Ljava/lang/String;
|
||||
public final fun getSubscriptionDetails ()Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
|
@ -1767,6 +1771,8 @@ public final class me/proton/core/auth/presentation/ui/UtilsKt {
|
|||
|
||||
public final class me/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment : me/proton/core/auth/presentation/ui/signup/SignupFragment {
|
||||
public static final field ARG_INPUT_ACCOUNT_TYPE Ljava/lang/String;
|
||||
public static final field ARG_INPUT_CANCELLABLE Ljava/lang/String;
|
||||
public static final field ARG_INPUT_EMAIL Ljava/lang/String;
|
||||
public static final field ARG_INPUT_SUBSCRIPTION_DETAILS Ljava/lang/String;
|
||||
public static final field Companion Lme/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment$Companion;
|
||||
public fun <init> ()V
|
||||
|
@ -1776,7 +1782,8 @@ public final class me/proton/core/auth/presentation/ui/signup/ChooseExternalEmai
|
|||
}
|
||||
|
||||
public final class me/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment$Companion {
|
||||
public final fun invoke (Lme/proton/core/account/domain/entity/AccountType;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)Lme/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment;
|
||||
public final fun invoke (Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;)Lme/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment;
|
||||
public static synthetic fun invoke$default (Lme/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment$Companion;Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Lme/proton/core/auth/presentation/entity/signup/SubscriptionDetails;ILjava/lang/Object;)Lme/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/auth/presentation/ui/signup/ChooseExternalEmailFragment_GeneratedInjector {
|
||||
|
@ -1785,6 +1792,7 @@ public abstract interface class me/proton/core/auth/presentation/ui/signup/Choos
|
|||
|
||||
public final class me/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment : me/proton/core/auth/presentation/ui/signup/SignupFragment {
|
||||
public static final field ARG_INPUT_ACCOUNT_TYPE Ljava/lang/String;
|
||||
public static final field ARG_INPUT_CANCELLABLE Ljava/lang/String;
|
||||
public static final field ARG_INPUT_DOMAIN Ljava/lang/String;
|
||||
public static final field ARG_INPUT_USERNAME Ljava/lang/String;
|
||||
public static final field Companion Lme/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment$Companion;
|
||||
|
@ -1795,7 +1803,8 @@ public final class me/proton/core/auth/presentation/ui/signup/ChooseInternalEmai
|
|||
}
|
||||
|
||||
public final class me/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment$Companion {
|
||||
public final fun invoke (Lme/proton/core/account/domain/entity/AccountType;Ljava/lang/String;Ljava/lang/String;)Lme/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment;
|
||||
public final fun invoke (Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Ljava/lang/String;)Lme/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment;
|
||||
public static synthetic fun invoke$default (Lme/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment$Companion;Lme/proton/core/account/domain/entity/AccountType;ZLjava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lme/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/auth/presentation/ui/signup/ChooseInternalEmailFragment_GeneratedInjector {
|
||||
|
@ -1813,12 +1822,19 @@ public abstract interface class me/proton/core/auth/presentation/ui/signup/Choos
|
|||
}
|
||||
|
||||
public final class me/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment : me/proton/core/auth/presentation/ui/signup/SignupFragment {
|
||||
public static final field ARG_INPUT_CANCELLABLE Ljava/lang/String;
|
||||
public static final field Companion Lme/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment$Companion;
|
||||
public fun <init> ()V
|
||||
public fun onBackPressed ()V
|
||||
public fun onViewCreated (Landroid/view/View;Landroid/os/Bundle;)V
|
||||
public fun showLoading (Z)V
|
||||
}
|
||||
|
||||
public final class me/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment$Companion {
|
||||
public final fun invoke (Z)Lme/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment;
|
||||
public static synthetic fun invoke$default (Lme/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment$Companion;ZILjava/lang/Object;)Lme/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment_GeneratedInjector {
|
||||
public abstract fun injectChooseUsernameFragment (Lme/proton/core/auth/presentation/ui/signup/ChooseUsernameFragment;)V
|
||||
}
|
||||
|
@ -2044,6 +2060,7 @@ public abstract class me/proton/core/auth/presentation/ui/signup/SignupFragment
|
|||
public abstract fun onBackPressed ()V
|
||||
public fun onCreate (Landroid/os/Bundle;)V
|
||||
public fun onUiComponentCreated (Landroidx/lifecycle/LifecycleOwner;Landroidx/activity/OnBackPressedDispatcherOwner;Landroidx/savedstate/SavedStateRegistryOwner;Lme/proton/core/presentation/utils/UiComponent;)V
|
||||
public fun setNavigationIcon (Landroidx/appcompat/widget/Toolbar;IZ)V
|
||||
public fun showError (Ljava/lang/String;)V
|
||||
public fun showIndefiniteError (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
|
||||
public static synthetic fun showIndefiniteError$default (Lme/proton/core/auth/presentation/ui/signup/SignupFragment;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
|
||||
|
@ -2852,11 +2869,11 @@ public final class me/proton/core/auth/presentation/viewmodel/signup/SignupViewM
|
|||
}
|
||||
|
||||
public final class me/proton/core/auth/presentation/viewmodel/signup/SignupViewModel_Factory : dagger/internal/Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lme/proton/core/auth/presentation/viewmodel/signup/SignupViewModel_Factory;
|
||||
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lme/proton/core/auth/presentation/viewmodel/signup/SignupViewModel_Factory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/auth/presentation/viewmodel/signup/SignupViewModel;
|
||||
public static fun newInstance (Lme/proton/core/humanverification/domain/HumanVerificationExternalInput;Lme/proton/core/auth/domain/usecase/signup/PerformCreateUser;Lme/proton/core/auth/domain/usecase/signup/PerformCreateExternalEmailUser;Lme/proton/core/crypto/common/keystore/KeyStoreCrypto;Lme/proton/core/plan/presentation/PlansOrchestrator;Lme/proton/core/payment/presentation/PaymentsOrchestrator;Lme/proton/core/auth/domain/usecase/PerformLogin;Lme/proton/core/challenge/domain/ChallengeManager;Lme/proton/core/auth/domain/usecase/signup/SignupChallengeConfig;Lme/proton/core/observability/domain/ObservabilityManager;Lme/proton/core/plan/domain/usecase/CanUpgradeToPaid;Lme/proton/core/plan/domain/IsDynamicPlanEnabled;Lme/proton/core/telemetry/domain/TelemetryManager;Landroidx/lifecycle/SavedStateHandle;)Lme/proton/core/auth/presentation/viewmodel/signup/SignupViewModel;
|
||||
public static fun newInstance (Lme/proton/core/humanverification/domain/HumanVerificationExternalInput;Lme/proton/core/auth/domain/usecase/signup/PerformCreateUser;Lme/proton/core/auth/domain/usecase/signup/PerformCreateExternalEmailUser;Lme/proton/core/auth/domain/usecase/signup/SetCreateAccountSuccess;Lme/proton/core/crypto/common/keystore/KeyStoreCrypto;Lme/proton/core/plan/presentation/PlansOrchestrator;Lme/proton/core/payment/presentation/PaymentsOrchestrator;Lme/proton/core/auth/domain/usecase/PerformLogin;Lme/proton/core/challenge/domain/ChallengeManager;Lme/proton/core/auth/domain/usecase/signup/SignupChallengeConfig;Lme/proton/core/observability/domain/ObservabilityManager;Lme/proton/core/plan/domain/usecase/CanUpgradeToPaid;Lme/proton/core/plan/domain/IsDynamicPlanEnabled;Lme/proton/core/telemetry/domain/TelemetryManager;Landroidx/lifecycle/SavedStateHandle;)Lme/proton/core/auth/presentation/viewmodel/signup/SignupViewModel;
|
||||
}
|
||||
|
||||
public final class me/proton/core/auth/presentation/viewmodel/signup/SignupViewModel_HiltModules {
|
||||
|
|
|
@ -383,9 +383,12 @@ class AuthOrchestrator @Inject constructor() {
|
|||
*/
|
||||
fun startSignupWorkflow(
|
||||
creatableAccountType: AccountType = AccountType.Internal,
|
||||
subscriptionDetails: SubscriptionDetails? = null) {
|
||||
cancellable: Boolean = true,
|
||||
email: String? = null,
|
||||
subscriptionDetails: SubscriptionDetails? = null
|
||||
) {
|
||||
checkRegistered(signUpWorkflowLauncher).launch(
|
||||
SignUpInput(creatableAccountType, subscriptionDetails)
|
||||
SignUpInput(creatableAccountType, cancellable, email, subscriptionDetails)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,5 +25,7 @@ import me.proton.core.account.domain.entity.AccountType
|
|||
@Parcelize
|
||||
data class SignUpInput(
|
||||
val creatableAccountType: AccountType,
|
||||
val cancellable: Boolean = true,
|
||||
val email: String? = null,
|
||||
val subscriptionDetails: SubscriptionDetails? = null
|
||||
) : Parcelable
|
||||
|
|
|
@ -79,21 +79,35 @@ class ChooseExternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
AccountType.valueOf(requireNotNull(requireArguments().getString(ARG_INPUT_ACCOUNT_TYPE)))
|
||||
}
|
||||
|
||||
private val cancellable: Boolean by lazy {
|
||||
requireArguments().getBoolean(ARG_INPUT_CANCELLABLE)
|
||||
}
|
||||
|
||||
private val email: String? by lazy {
|
||||
requireArguments().getString(ARG_INPUT_EMAIL)
|
||||
}
|
||||
|
||||
private val subscriptionDetails: SubscriptionDetails? by lazy {
|
||||
requireArguments().getParcelable(ARG_INPUT_SUBSCRIPTION_DETAILS)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
signupViewModel.onFinish()
|
||||
activity?.finish()
|
||||
if (cancellable) {
|
||||
signupViewModel.onFinish()
|
||||
activity?.finish()
|
||||
} else {
|
||||
showError(getString(R.string.auth_signup_error_create_to_continue))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.apply {
|
||||
toolbar.setNavigationIcon(R.drawable.ic_proton_close, cancellable)
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
|
||||
emailInput.text = email
|
||||
emailInput.apply {
|
||||
setOnFocusLostListener { _, _ ->
|
||||
validateEmail()
|
||||
|
@ -139,7 +153,7 @@ class ChooseExternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
}
|
||||
|
||||
private fun onSwitchInternal(username: String? = null, domain: String? = null) {
|
||||
parentFragmentManager.replaceByInternalEmailChooser(creatableAccountType, username, domain)
|
||||
parentFragmentManager.replaceByInternalEmailChooser(creatableAccountType, cancellable, username, domain)
|
||||
}
|
||||
|
||||
private fun onExternalEmailAvailable(email: String) {
|
||||
|
@ -166,14 +180,20 @@ class ChooseExternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
|
||||
companion object {
|
||||
const val ARG_INPUT_ACCOUNT_TYPE = "arg.accountType"
|
||||
const val ARG_INPUT_CANCELLABLE = "arg.cancellable"
|
||||
const val ARG_INPUT_SUBSCRIPTION_DETAILS = "arg.subscriptionDetails"
|
||||
const val ARG_INPUT_EMAIL = "arg.email"
|
||||
|
||||
operator fun invoke(
|
||||
creatableAccountType: AccountType,
|
||||
subscriptionDetails: SubscriptionDetails?
|
||||
cancellable: Boolean = true,
|
||||
email: String? = null,
|
||||
subscriptionDetails: SubscriptionDetails? = null
|
||||
) = ChooseExternalEmailFragment().apply {
|
||||
arguments = bundleOf(
|
||||
ARG_INPUT_ACCOUNT_TYPE to creatableAccountType.name,
|
||||
ARG_INPUT_CANCELLABLE to cancellable,
|
||||
ARG_INPUT_EMAIL to email,
|
||||
ARG_INPUT_SUBSCRIPTION_DETAILS to subscriptionDetails
|
||||
)
|
||||
}
|
||||
|
|
|
@ -83,16 +83,22 @@ class ChooseInternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
|
||||
private val username by lazy { requireArguments().getString(ARG_INPUT_USERNAME) }
|
||||
private val domain by lazy { requireArguments().getString(ARG_INPUT_DOMAIN) }
|
||||
private val cancellable: Boolean by lazy { requireArguments().getBoolean(ARG_INPUT_CANCELLABLE) }
|
||||
|
||||
override fun onBackPressed() {
|
||||
signupViewModel.onFinish()
|
||||
activity?.finish()
|
||||
if (cancellable) {
|
||||
signupViewModel.onFinish()
|
||||
activity?.finish()
|
||||
} else {
|
||||
showError(getString(R.string.auth_signup_error_create_to_continue))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.apply {
|
||||
toolbar.setNavigationIcon(R.drawable.ic_proton_close, cancellable)
|
||||
toolbar.setNavigationOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
usernameInput.apply {
|
||||
|
@ -113,6 +119,7 @@ class ChooseInternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
separatorView.visibility = View.GONE
|
||||
footnoteText.visibility = View.GONE
|
||||
}
|
||||
|
||||
AccountType.External -> {
|
||||
switchButton.visibility = View.VISIBLE
|
||||
separatorView.visibility = View.VISIBLE
|
||||
|
@ -131,7 +138,12 @@ class ChooseInternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
is State.Processing -> showLoading(true)
|
||||
is State.Ready -> onReady(it.username, it.domain, it.domains)
|
||||
is State.Success -> onUsernameAvailable(it.username, it.domain)
|
||||
is State.Error.DomainsNotAvailable -> onDomainsNotAvailable(it.error.getUserMessage(resources))
|
||||
is State.Error.DomainsNotAvailable -> onDomainsNotAvailable(
|
||||
it.error.getUserMessage(
|
||||
resources
|
||||
)
|
||||
)
|
||||
|
||||
is State.Error.Message -> onError(it.error.getUserMessage(resources))
|
||||
}.exhaustive
|
||||
}
|
||||
|
@ -159,7 +171,7 @@ class ChooseInternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
}
|
||||
|
||||
private fun onSwitchClicked() {
|
||||
parentFragmentManager.replaceByExternalEmailChooser(creatableAccountType)
|
||||
parentFragmentManager.replaceByExternalEmailChooser(creatableAccountType, cancellable)
|
||||
}
|
||||
|
||||
private fun onReady(username: String?, domain: String?, domains: List<Domain>) {
|
||||
|
@ -219,18 +231,21 @@ class ChooseInternalEmailFragment : SignupFragment(R.layout.fragment_signup_choo
|
|||
|
||||
companion object {
|
||||
const val ARG_INPUT_ACCOUNT_TYPE = "arg.accountType"
|
||||
const val ARG_INPUT_CANCELLABLE = "arg.cancellable"
|
||||
const val ARG_INPUT_USERNAME = "arg.username"
|
||||
const val ARG_INPUT_DOMAIN = "arg.domain"
|
||||
|
||||
operator fun invoke(
|
||||
creatableAccountType: AccountType,
|
||||
username: String?,
|
||||
domain: String?
|
||||
cancellable: Boolean = true,
|
||||
username: String? = null,
|
||||
domain: String? = null,
|
||||
) = ChooseInternalEmailFragment().apply {
|
||||
arguments = bundleOf(
|
||||
ARG_INPUT_ACCOUNT_TYPE to creatableAccountType.name,
|
||||
ARG_INPUT_CANCELLABLE to cancellable,
|
||||
ARG_INPUT_USERNAME to username,
|
||||
ARG_INPUT_DOMAIN to domain
|
||||
ARG_INPUT_DOMAIN to domain,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package me.proton.core.auth.presentation.ui.signup
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
|
@ -55,15 +56,22 @@ class ChooseUsernameFragment : SignupFragment(R.layout.fragment_signup_choose_us
|
|||
private val signupViewModel by activityViewModels<SignupViewModel>()
|
||||
private val binding by viewBinding(FragmentSignupChooseUsernameBinding::bind)
|
||||
|
||||
private val cancellable: Boolean by lazy { requireArguments().getBoolean(ARG_INPUT_CANCELLABLE) }
|
||||
|
||||
override fun onBackPressed() {
|
||||
signupViewModel.onFinish()
|
||||
activity?.finish()
|
||||
if (cancellable) {
|
||||
signupViewModel.onFinish()
|
||||
activity?.finish()
|
||||
} else {
|
||||
showError(getString(R.string.auth_signup_error_create_to_continue))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.apply {
|
||||
toolbar.setNavigationIcon(R.drawable.ic_proton_close, cancellable)
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
|
||||
usernameInput.apply {
|
||||
|
@ -128,4 +136,16 @@ class ChooseUsernameFragment : SignupFragment(R.layout.fragment_signup_choose_us
|
|||
nextButton.setIdle()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ARG_INPUT_CANCELLABLE = "arg.cancellable"
|
||||
|
||||
operator fun invoke(
|
||||
cancellable: Boolean = true,
|
||||
) = ChooseUsernameFragment().apply {
|
||||
arguments = bundleOf(
|
||||
ARG_INPUT_CANCELLABLE to cancellable
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,9 +83,10 @@ internal fun FragmentManager.showTermsConditions() {
|
|||
}
|
||||
|
||||
internal fun FragmentManager.showUsernameChooser(
|
||||
cancellable: Boolean = true,
|
||||
containerId: Int = android.R.id.content
|
||||
) = findFragmentByTag(TAG_USERNAME_CHOOSER) ?: run {
|
||||
val fragment = ChooseUsernameFragment()
|
||||
val fragment = ChooseUsernameFragment(cancellable)
|
||||
inTransaction {
|
||||
setCustomAnimations(0, 0)
|
||||
add(containerId, fragment, TAG_USERNAME_CHOOSER)
|
||||
|
@ -95,11 +96,12 @@ internal fun FragmentManager.showUsernameChooser(
|
|||
|
||||
internal fun FragmentManager.showInternalEmailChooser(
|
||||
creatableAccountType: AccountType,
|
||||
cancellable: Boolean = true,
|
||||
username: String? = null,
|
||||
domain: String? = null,
|
||||
containerId: Int = android.R.id.content
|
||||
) = findFragmentByTag(TAG_INTERNAL_EMAIL_CHOOSER) ?: run {
|
||||
val fragment = ChooseInternalEmailFragment(creatableAccountType, username, domain)
|
||||
val fragment = ChooseInternalEmailFragment(creatableAccountType, cancellable, username, domain)
|
||||
inTransaction {
|
||||
setCustomAnimations(0, 0)
|
||||
add(containerId, fragment, TAG_INTERNAL_EMAIL_CHOOSER)
|
||||
|
@ -109,10 +111,12 @@ internal fun FragmentManager.showInternalEmailChooser(
|
|||
|
||||
internal fun FragmentManager.showExternalEmailChooser(
|
||||
creatableAccountType: AccountType,
|
||||
cancellable: Boolean = true,
|
||||
email: String? = null,
|
||||
subscriptionDetails: SubscriptionDetails? = null,
|
||||
containerId: Int = android.R.id.content
|
||||
) = findFragmentByTag(TAG_EXTERNAL_EMAIL_CHOOSER) ?: run {
|
||||
val fragment = ChooseExternalEmailFragment(creatableAccountType, subscriptionDetails)
|
||||
val fragment = ChooseExternalEmailFragment(creatableAccountType, cancellable, email, subscriptionDetails)
|
||||
inTransaction {
|
||||
setCustomAnimations(0, 0)
|
||||
add(containerId, fragment, TAG_EXTERNAL_EMAIL_CHOOSER)
|
||||
|
@ -122,11 +126,12 @@ internal fun FragmentManager.showExternalEmailChooser(
|
|||
|
||||
internal fun FragmentManager.replaceByInternalEmailChooser(
|
||||
creatableAccountType: AccountType,
|
||||
cancellable: Boolean = true,
|
||||
username: String? = null,
|
||||
domain: String? = null,
|
||||
containerId: Int = android.R.id.content
|
||||
) = findFragmentByTag(TAG_INTERNAL_EMAIL_CHOOSER) ?: run {
|
||||
val fragment = ChooseInternalEmailFragment(creatableAccountType, username, domain)
|
||||
val fragment = ChooseInternalEmailFragment(creatableAccountType, cancellable, username, domain)
|
||||
inTransaction {
|
||||
setCustomAnimations(0, 0)
|
||||
replace(containerId, fragment, TAG_INTERNAL_EMAIL_CHOOSER)
|
||||
|
@ -136,10 +141,12 @@ internal fun FragmentManager.replaceByInternalEmailChooser(
|
|||
|
||||
internal fun FragmentManager.replaceByExternalEmailChooser(
|
||||
creatableAccountType: AccountType,
|
||||
cancellable: Boolean = true,
|
||||
email: String? = null,
|
||||
subscriptionDetails: SubscriptionDetails? = null,
|
||||
containerId: Int = android.R.id.content
|
||||
) = findFragmentByTag(TAG_EXTERNAL_EMAIL_CHOOSER) ?: run {
|
||||
val fragment = ChooseExternalEmailFragment(creatableAccountType, subscriptionDetails)
|
||||
val fragment = ChooseExternalEmailFragment(creatableAccountType, cancellable, email, subscriptionDetails)
|
||||
inTransaction {
|
||||
setCustomAnimations(0, 0)
|
||||
replace(containerId, fragment, TAG_EXTERNAL_EMAIL_CHOOSER)
|
||||
|
|
|
@ -103,9 +103,19 @@ class SignupActivity : AuthActivity<ActivitySignupBinding>(ActivitySignupBinding
|
|||
if (savedInstanceState == null) {
|
||||
with(supportFragmentManager) {
|
||||
when (input.creatableAccountType) {
|
||||
AccountType.Username -> showUsernameChooser()
|
||||
AccountType.Internal -> showInternalEmailChooser(input.creatableAccountType)
|
||||
AccountType.External -> showExternalEmailChooser(input.creatableAccountType, input.subscriptionDetails)
|
||||
AccountType.Username -> showUsernameChooser(
|
||||
cancellable = input.cancellable
|
||||
)
|
||||
AccountType.Internal -> showInternalEmailChooser(
|
||||
creatableAccountType = input.creatableAccountType,
|
||||
cancellable = input.cancellable
|
||||
)
|
||||
AccountType.External -> showExternalEmailChooser(
|
||||
creatableAccountType = input.creatableAccountType,
|
||||
cancellable = input.cancellable,
|
||||
email = input.email,
|
||||
subscriptionDetails = input.subscriptionDetails
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
package me.proton.core.auth.presentation.ui.signup
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import me.proton.core.auth.presentation.R
|
||||
import me.proton.core.presentation.ui.ProtonSecureFragment
|
||||
|
@ -63,4 +66,11 @@ abstract class SignupFragment : ProtonSecureFragment, UiComponentProductMetricsD
|
|||
length = Snackbar.LENGTH_INDEFINITE,
|
||||
)
|
||||
}
|
||||
|
||||
open fun Toolbar.setNavigationIcon(@DrawableRes res: Int, visible: Boolean) {
|
||||
navigationIcon = when {
|
||||
visible -> ResourcesCompat.getDrawable(resources, res, null)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.parcelize.Parcelize
|
||||
import me.proton.core.account.domain.entity.AccountType
|
||||
import me.proton.core.auth.domain.usecase.PerformLogin
|
||||
import me.proton.core.auth.domain.usecase.signup.SetCreateAccountSuccess
|
||||
import me.proton.core.auth.domain.usecase.signup.PerformCreateExternalEmailUser
|
||||
import me.proton.core.auth.domain.usecase.signup.PerformCreateUser
|
||||
import me.proton.core.auth.domain.usecase.signup.SignupChallengeConfig
|
||||
|
@ -57,15 +58,9 @@ import me.proton.core.observability.domain.metrics.SignupAccountCreationTotal
|
|||
import me.proton.core.observability.domain.metrics.SignupScreenViewTotalV1
|
||||
import me.proton.core.observability.domain.metrics.common.AccountTypeLabels
|
||||
import me.proton.core.observability.domain.metrics.common.toObservabilityAccountType
|
||||
import me.proton.core.payment.domain.entity.Currency
|
||||
import me.proton.core.payment.domain.entity.ProtonPaymentToken
|
||||
import me.proton.core.payment.domain.entity.SubscriptionCycle
|
||||
import me.proton.core.payment.presentation.LogTag
|
||||
import me.proton.core.payment.presentation.PaymentsOrchestrator
|
||||
import me.proton.core.plan.domain.IsDynamicPlanEnabled
|
||||
import me.proton.core.plan.domain.entity.SubscriptionManagement
|
||||
import me.proton.core.plan.domain.usecase.CanUpgradeToPaid
|
||||
import me.proton.core.plan.domain.usecase.PerformSubscribe
|
||||
import me.proton.core.plan.presentation.PlansOrchestrator
|
||||
import me.proton.core.presentation.savedstate.flowState
|
||||
import me.proton.core.presentation.savedstate.state
|
||||
|
@ -73,7 +68,6 @@ import me.proton.core.presentation.utils.InputValidationResult
|
|||
import me.proton.core.telemetry.domain.TelemetryContext
|
||||
import me.proton.core.telemetry.domain.TelemetryManager
|
||||
import me.proton.core.user.domain.entity.createUserType
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import me.proton.core.util.kotlin.catchWhen
|
||||
import me.proton.core.util.kotlin.coroutine.withResultContext
|
||||
import javax.inject.Inject
|
||||
|
@ -83,6 +77,7 @@ internal class SignupViewModel @Inject constructor(
|
|||
private val humanVerificationExternalInput: HumanVerificationExternalInput,
|
||||
private val performCreateUser: PerformCreateUser,
|
||||
private val performCreateExternalEmailUser: PerformCreateExternalEmailUser,
|
||||
private val setCreateAccountSuccess: SetCreateAccountSuccess,
|
||||
private val keyStoreCrypto: KeyStoreCrypto,
|
||||
private val plansOrchestrator: PlansOrchestrator,
|
||||
private val paymentsOrchestrator: PaymentsOrchestrator,
|
||||
|
@ -262,7 +257,7 @@ internal class SignupViewModel @Inject constructor(
|
|||
referrer = null,
|
||||
type = currentAccountType.createUserType(),
|
||||
domain = domain
|
||||
)
|
||||
).also { setCreateAccountSuccess() }
|
||||
}
|
||||
emit(State.CreateUserSuccess(result.id, username, encryptedPassword))
|
||||
}.catchWhen(Throwable::userAlreadyExists) {
|
||||
|
@ -282,7 +277,7 @@ internal class SignupViewModel @Inject constructor(
|
|||
email = externalEmail,
|
||||
password = encryptedPassword,
|
||||
referrer = null
|
||||
)
|
||||
).also { setCreateAccountSuccess() }
|
||||
}
|
||||
emit(State.CreateUserSuccess(userId.id, externalEmail, encryptedPassword))
|
||||
}.catchWhen(Throwable::userAlreadyExists) {
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
<string name="auth_signup_skip_recovery">Skip</string>
|
||||
<string name="auth_signup_set_recovery">Set recovery method</string>
|
||||
<string name="auth_signup_no_connectivity">No connectivity to display Terms and Conditions.</string>
|
||||
<string name="auth_signup_error_create_to_continue">Please create an account to continue</string>
|
||||
<string name="auth_signup_error_username_blank">Username must not be blank.</string>
|
||||
<string name="auth_signup_error_passwords_do_not_match">Passwords do not match.</string>
|
||||
<string name="auth_signup_validation_password_length">Password should be at least 8 characters long.</string>
|
||||
|
|
|
@ -32,6 +32,7 @@ import me.proton.core.account.domain.entity.AccountType
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.auth.domain.usecase.GetPrimaryUser
|
||||
import me.proton.core.auth.domain.usecase.PerformLogin
|
||||
import me.proton.core.auth.domain.usecase.signup.SetCreateAccountSuccess
|
||||
import me.proton.core.auth.domain.usecase.signup.PerformCreateExternalEmailUser
|
||||
import me.proton.core.auth.domain.usecase.signup.PerformCreateUser
|
||||
import me.proton.core.auth.domain.usecase.signup.SignupChallengeConfig
|
||||
|
@ -101,6 +102,9 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
@MockK
|
||||
private lateinit var performLogin: PerformLogin
|
||||
|
||||
@MockK(relaxed = true)
|
||||
private lateinit var setCreateAccountSuccess: SetCreateAccountSuccess
|
||||
|
||||
@MockK(relaxed = true)
|
||||
private lateinit var challengeManager: ChallengeManager
|
||||
|
||||
|
@ -208,6 +212,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
humanVerificationExternalInput,
|
||||
performCreateUser,
|
||||
performCreateExternalUser,
|
||||
setCreateAccountSuccess,
|
||||
keyStoreCrypto,
|
||||
plansOrchestrator,
|
||||
paymentsOrchestrator,
|
||||
|
@ -279,6 +284,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
domain = any()
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,6 +322,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
domain = any()
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,6 +360,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
domain = any()
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,6 +398,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
domain = any()
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,6 +437,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
domain = any()
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,6 +490,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
domain = any()
|
||||
)
|
||||
}
|
||||
coVerify(exactly = 0) { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,6 +517,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
referrer = null
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,6 +565,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
referrer = null
|
||||
)
|
||||
}
|
||||
coVerify(exactly = 0) { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,6 +606,7 @@ class SignupViewModelTest : ArchTest by ArchTest(), CoroutinesTest by Coroutines
|
|||
referrer = null
|
||||
)
|
||||
}
|
||||
coVerify { setCreateAccountSuccess.invoke() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ import me.proton.core.account.domain.entity.AccountType
|
|||
import me.proton.core.accountmanager.domain.AccountManager
|
||||
import me.proton.core.accountmanager.domain.getPrimaryAccount
|
||||
import me.proton.core.accountmanager.presentation.observe
|
||||
import me.proton.core.accountmanager.presentation.onAccountCreateAccountFailed
|
||||
import me.proton.core.accountmanager.presentation.onAccountCreateAccountNeeded
|
||||
import me.proton.core.accountmanager.presentation.onAccountCreateAddressFailed
|
||||
import me.proton.core.accountmanager.presentation.onAccountCreateAddressNeeded
|
||||
import me.proton.core.accountmanager.presentation.onAccountMigrationNeeded
|
||||
|
@ -113,6 +115,8 @@ class AccountViewModel @Inject constructor(
|
|||
.onSessionSecondFactorFailed { signIn(username = it.username) }
|
||||
.onAccountTwoPassModeNeeded { startTwoPassModeWorkflow(it) }
|
||||
.onAccountCreateAddressNeeded { startChooseAddressWorkflow(it) }
|
||||
.onAccountCreateAccountNeeded { startSignupWorkflow(accountType, cancellable = false) }
|
||||
.onAccountCreateAccountFailed { accountManager.disableAccount(it.userId) }
|
||||
.onAccountTwoPassModeFailed { accountManager.disableAccount(it.userId) }
|
||||
.onAccountCreateAddressFailed { accountManager.disableAccount(it.userId) }
|
||||
.onAccountMigrationNeeded { context.showToast("MigrationNeeded") }
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.payment.domain.extension
|
||||
|
||||
import me.proton.core.payment.domain.entity.Purchase
|
||||
import me.proton.core.payment.domain.entity.PurchaseState
|
||||
import me.proton.core.payment.domain.repository.PurchaseRepository
|
||||
import me.proton.core.util.kotlin.annotation.ExcludeFromCoverage
|
||||
|
||||
@ExcludeFromCoverage
|
||||
public suspend fun PurchaseRepository.getPurchaseOrNull(
|
||||
state: PurchaseState
|
||||
): Purchase? = getPurchases().firstOrNull { it.purchaseState == state }
|
Loading…
Reference in New Issue