Trigger backup-id upload before allowing user to pay.

This commit is contained in:
Alex Hart
2025-03-10 12:08:02 -03:00
committed by Greyson Parrelli
parent 862628fc28
commit 5ec3371b9a
8 changed files with 65 additions and 9 deletions

View File

@@ -142,6 +142,16 @@ object BackupRepository {
}
}
/**
* Triggers backup id reservation. As documented, this is safe to perform multiple times.
*/
@WorkerThread
fun triggerBackupIdReservation(): NetworkResult<Unit> {
val messageBackupKey = SignalStore.backup.messageBackupKey
val mediaRootBackupKey = SignalStore.backup.mediaRootBackupKey
return SignalNetwork.archive.triggerBackupIdReservation(messageBackupKey, mediaRootBackupKey, SignalStore.account.requireAci())
}
/**
* Refreshes backup via server
*/

View File

@@ -14,12 +14,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.rx3.asFlowable
import org.signal.core.ui.Dialogs
import org.signal.core.util.getSerializableCompat
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
@@ -121,6 +123,7 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
composable(route = MessageBackupsStage.Route.TYPE_SELECTION.name) {
MessageBackupsTypeSelectionScreen(
stage = state.stage,
paymentReadyState = state.paymentReadyState,
currentBackupTier = state.currentMessageBackupTier,
selectedBackupTier = state.selectedMessageBackupTier,
availableBackupTypes = state.availableBackupTypes,
@@ -152,6 +155,14 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
requireActivity().finishAfterTransition()
}
}
if (state.paymentReadyState == MessageBackupsFlowState.PaymentReadyState.FAILED) {
Dialogs.SimpleMessageDialog(
message = stringResource(R.string.MessageBackupsFlowFragment__a_network_failure_occurred),
dismiss = stringResource(android.R.string.ok),
onDismiss = { requireActivity().finishAfterTransition() }
)
}
}
override fun onUserLaunchedAnExternalApplication() = error("Not supported by this fragment.")

View File

@@ -18,5 +18,12 @@ data class MessageBackupsFlowState(
val startScreen: MessageBackupsStage,
val stage: MessageBackupsStage = startScreen,
val accountEntropyPool: AccountEntropyPool = SignalStore.account.accountEntropyPool,
val failure: Throwable? = null
)
val failure: Throwable? = null,
val paymentReadyState: PaymentReadyState = PaymentReadyState.NOT_READY
) {
enum class PaymentReadyState {
NOT_READY,
READY,
FAILED
}
}

View File

@@ -69,6 +69,22 @@ class MessageBackupsFlowViewModel(
init {
check(SignalStore.backup.backupTier != MessageBackupTier.PAID) { "This screen does not support cancellation or downgrades." }
viewModelScope.launch {
val result = withContext(Dispatchers.IO) {
BackupRepository.triggerBackupIdReservation()
}
result.runIfSuccessful {
Log.d(TAG, "Successfully triggered backup id reservation.")
internalStateFlow.update { it.copy(paymentReadyState = MessageBackupsFlowState.PaymentReadyState.READY) }
}
result.runOnStatusCodeError {
Log.d(TAG, "Failed to trigger backup id reservation. ($it)")
internalStateFlow.update { it.copy(paymentReadyState = MessageBackupsFlowState.PaymentReadyState.FAILED) }
}
}
viewModelScope.launch {
internalStateFlow.update {
it.copy(

View File

@@ -70,6 +70,7 @@ import org.signal.core.ui.R as CoreUiR
@Composable
fun MessageBackupsTypeSelectionScreen(
stage: MessageBackupsStage,
paymentReadyState: MessageBackupsFlowState.PaymentReadyState,
currentBackupTier: MessageBackupTier?,
selectedBackupTier: MessageBackupTier?,
availableBackupTypes: List<MessageBackupsType>,
@@ -160,7 +161,7 @@ fun MessageBackupsTypeSelectionScreen(
Buttons.LargePrimary(
onClick = onNextClicked,
enabled = selectedBackupTier != currentBackupTier && selectedBackupTier != null,
enabled = selectedBackupTier != currentBackupTier && selectedBackupTier != null && paymentReadyState == MessageBackupsFlowState.PaymentReadyState.READY,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = if (hasCurrentBackupTier) 10.dp else 16.dp)
@@ -200,7 +201,8 @@ private fun MessageBackupsTypeSelectionScreenPreview() {
onNavigationClick = {},
onReadMoreClicked = {},
onNextClicked = {},
currentBackupTier = null
currentBackupTier = null,
paymentReadyState = MessageBackupsFlowState.PaymentReadyState.READY
)
}
}
@@ -219,7 +221,8 @@ private fun MessageBackupsTypeSelectionScreenWithCurrentTierPreview() {
onNavigationClick = {},
onReadMoreClicked = {},
onNextClicked = {},
currentBackupTier = MessageBackupTier.PAID
currentBackupTier = MessageBackupTier.PAID,
paymentReadyState = MessageBackupsFlowState.PaymentReadyState.READY
)
}
}