Backups subscription flow odds and ends.
This commit is contained in:
parent
97974291d2
commit
89bfba3ee9
5 changed files with 35 additions and 14 deletions
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
package org.thoughtcrime.securesms.backup.v2.ui.subscription
|
package org.thoughtcrime.securesms.backup.v2.ui.subscription
|
||||||
|
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
@ -38,6 +39,7 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
|
||||||
@Composable
|
@Composable
|
||||||
override fun FragmentContent() {
|
override fun FragmentContent() {
|
||||||
val state by viewModel.stateFlow.collectAsState()
|
val state by viewModel.stateFlow.collectAsState()
|
||||||
|
val pin by viewModel.pinState
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
val checkoutDelegate = remember {
|
val checkoutDelegate = remember {
|
||||||
|
@ -57,8 +59,12 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
navController.setLifecycleOwner(this@MessageBackupsFlowFragment)
|
navController.setLifecycleOwner(this@MessageBackupsFlowFragment)
|
||||||
navController.setOnBackPressedDispatcher(requireActivity().onBackPressedDispatcher)
|
|
||||||
navController.enableOnBackPressed(true)
|
requireActivity().onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
viewModel.goToPreviousScreen()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Nav.Host(
|
Nav.Host(
|
||||||
|
@ -84,7 +90,7 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
|
||||||
|
|
||||||
composable(route = MessageBackupsScreen.PIN_CONFIRMATION.name) {
|
composable(route = MessageBackupsScreen.PIN_CONFIRMATION.name) {
|
||||||
MessageBackupsPinConfirmationScreen(
|
MessageBackupsPinConfirmationScreen(
|
||||||
pin = state.pin,
|
pin = pin,
|
||||||
onPinChanged = viewModel::onPinEntryUpdated,
|
onPinChanged = viewModel::onPinEntryUpdated,
|
||||||
pinKeyboardType = state.pinKeyboardType,
|
pinKeyboardType = state.pinKeyboardType,
|
||||||
onPinKeyboardTypeSelected = viewModel::onPinKeyboardTypeUpdated,
|
onPinKeyboardTypeSelected = viewModel::onPinKeyboardTypeUpdated,
|
||||||
|
|
|
@ -17,7 +17,6 @@ data class MessageBackupsFlowState(
|
||||||
val availableBackupTypes: List<MessageBackupsType> = emptyList(),
|
val availableBackupTypes: List<MessageBackupsType> = emptyList(),
|
||||||
val selectedPaymentMethod: InAppPaymentData.PaymentMethodType? = null,
|
val selectedPaymentMethod: InAppPaymentData.PaymentMethodType? = null,
|
||||||
val availablePaymentMethods: List<InAppPaymentData.PaymentMethodType> = emptyList(),
|
val availablePaymentMethods: List<InAppPaymentData.PaymentMethodType> = emptyList(),
|
||||||
val pin: String = "",
|
|
||||||
val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType,
|
val pinKeyboardType: PinKeyboardType = SignalStore.pin.keyboardType,
|
||||||
val inAppPayment: InAppPaymentTable.InAppPayment? = null,
|
val inAppPayment: InAppPaymentTable.InAppPayment? = null,
|
||||||
val startScreen: MessageBackupsScreen,
|
val startScreen: MessageBackupsScreen,
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.backup.v2.ui.subscription
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -43,7 +44,10 @@ class MessageBackupsFlowViewModel : ViewModel() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val internalPinState = mutableStateOf("")
|
||||||
|
|
||||||
val stateFlow: StateFlow<MessageBackupsFlowState> = internalStateFlow
|
val stateFlow: StateFlow<MessageBackupsFlowState> = internalStateFlow
|
||||||
|
val pinState: State<String> = internalPinState
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
@ -58,11 +62,14 @@ class MessageBackupsFlowViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goToNextScreen() {
|
fun goToNextScreen() {
|
||||||
|
val pinSnapshot = pinState.value
|
||||||
|
internalPinState.value = ""
|
||||||
|
|
||||||
internalStateFlow.update {
|
internalStateFlow.update {
|
||||||
val nextScreen = when (it.screen) {
|
val nextScreen = when (it.screen) {
|
||||||
MessageBackupsScreen.EDUCATION -> MessageBackupsScreen.PIN_EDUCATION
|
MessageBackupsScreen.EDUCATION -> MessageBackupsScreen.PIN_EDUCATION
|
||||||
MessageBackupsScreen.PIN_EDUCATION -> MessageBackupsScreen.PIN_CONFIRMATION
|
MessageBackupsScreen.PIN_EDUCATION -> MessageBackupsScreen.PIN_CONFIRMATION
|
||||||
MessageBackupsScreen.PIN_CONFIRMATION -> validatePinAndUpdateState(it.pin)
|
MessageBackupsScreen.PIN_CONFIRMATION -> validatePinAndUpdateState(pinSnapshot)
|
||||||
MessageBackupsScreen.TYPE_SELECTION -> validateTypeAndUpdateState(it.selectedMessageBackupTier!!)
|
MessageBackupsScreen.TYPE_SELECTION -> validateTypeAndUpdateState(it.selectedMessageBackupTier!!)
|
||||||
MessageBackupsScreen.CHECKOUT_SHEET -> validateGatewayAndUpdateState(it)
|
MessageBackupsScreen.CHECKOUT_SHEET -> validateGatewayAndUpdateState(it)
|
||||||
MessageBackupsScreen.CREATING_IN_APP_PAYMENT -> error("This is driven by an async coroutine.")
|
MessageBackupsScreen.CREATING_IN_APP_PAYMENT -> error("This is driven by an async coroutine.")
|
||||||
|
@ -107,10 +114,7 @@ class MessageBackupsFlowViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPinEntryUpdated(pin: String) {
|
fun onPinEntryUpdated(pin: String) {
|
||||||
// TODO [alex] -- shouldn't store this in a flow
|
internalPinState.value = pin
|
||||||
internalStateFlow.update {
|
|
||||||
it.copy(pin = pin)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPinKeyboardTypeUpdated(pinKeyboardType: PinKeyboardType) {
|
fun onPinKeyboardTypeUpdated(pinKeyboardType: PinKeyboardType) {
|
||||||
|
@ -137,13 +141,15 @@ class MessageBackupsFlowViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateTypeAndUpdateState(tier: MessageBackupTier): MessageBackupsScreen {
|
private fun validateTypeAndUpdateState(tier: MessageBackupTier): MessageBackupsScreen {
|
||||||
SignalStore.backup.areBackupsEnabled = true
|
|
||||||
SignalStore.backup.backupTier = tier
|
|
||||||
|
|
||||||
// TODO [message-backups] - Does anything need to be kicked off?
|
// TODO [message-backups] - Does anything need to be kicked off?
|
||||||
|
|
||||||
return when (tier) {
|
return when (tier) {
|
||||||
MessageBackupTier.FREE -> MessageBackupsScreen.COMPLETED
|
MessageBackupTier.FREE -> {
|
||||||
|
SignalStore.backup.areBackupsEnabled = true
|
||||||
|
SignalStore.backup.backupTier = MessageBackupTier.FREE
|
||||||
|
|
||||||
|
MessageBackupsScreen.COMPLETED
|
||||||
|
}
|
||||||
MessageBackupTier.PAID -> MessageBackupsScreen.CHECKOUT_SHEET
|
MessageBackupTier.PAID -> MessageBackupsScreen.CHECKOUT_SHEET
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.res.dimensionResource
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
@ -99,7 +100,8 @@ fun MessageBackupsPinConfirmationScreen(
|
||||||
onDone = { onNextClick() }
|
onDone = { onNextClick() }
|
||||||
),
|
),
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
keyboardType = keyboardType
|
keyboardType = keyboardType,
|
||||||
|
imeAction = ImeAction.Done
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 72.dp)
|
.padding(top = 72.dp)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.signal.donations.PaymentSourceType
|
||||||
import org.signal.donations.StripeApi
|
import org.signal.donations.StripeApi
|
||||||
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation
|
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation
|
||||||
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialRequestContext
|
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialRequestContext
|
||||||
|
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||||
import org.thoughtcrime.securesms.badges.Badges
|
import org.thoughtcrime.securesms.badges.Badges
|
||||||
import org.thoughtcrime.securesms.badges.models.Badge
|
import org.thoughtcrime.securesms.badges.models.Badge
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository
|
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository
|
||||||
|
@ -464,6 +465,10 @@ class InAppPaymentValues internal constructor(store: KeyValueStore) : SignalStor
|
||||||
markDonationManuallyCancelled()
|
markDonationManuallyCancelled()
|
||||||
} else {
|
} else {
|
||||||
markBackupSubscriptionpManuallyCancelled()
|
markBackupSubscriptionpManuallyCancelled()
|
||||||
|
|
||||||
|
// TODO [message-backups] -- Handle downgrades?
|
||||||
|
SignalStore.backup.areBackupsEnabled = false
|
||||||
|
SignalStore.backup.backupTier = null
|
||||||
}
|
}
|
||||||
|
|
||||||
val subscriber = InAppPaymentsRepository.getSubscriber(subscriberType)
|
val subscriber = InAppPaymentsRepository.getSubscriber(subscriberType)
|
||||||
|
@ -504,6 +509,9 @@ class InAppPaymentValues internal constructor(store: KeyValueStore) : SignalStor
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clearBackupSubscriptionManuallyCancelled()
|
clearBackupSubscriptionManuallyCancelled()
|
||||||
|
|
||||||
|
SignalStore.backup.areBackupsEnabled = true
|
||||||
|
SignalStore.backup.backupTier = MessageBackupTier.PAID
|
||||||
}
|
}
|
||||||
|
|
||||||
val subscriber = InAppPaymentsRepository.requireSubscriber(subscriberType)
|
val subscriber = InAppPaymentsRepository.requireSubscriber(subscriberType)
|
||||||
|
|
Loading…
Add table
Reference in a new issue