From b6b6f7a52798f61ad25820cbe91ed41582ea95b8 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 20 May 2025 16:09:43 -0300 Subject: [PATCH] Allow free tier subscription if Google Play Billing is not available. --- .../securesms/backup/v2/BackupRepository.kt | 12 ++++++++--- .../app/backups/BackupsSettingsViewModel.kt | 15 ++++++------- .../remote/RemoteBackupsSettingsFragment.kt | 21 ++++++++++++++----- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index e289a2bd13..6f2be2abc4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.attachments.Attachment import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.attachments.Cdn import org.thoughtcrime.securesms.attachments.DatabaseAttachment +import org.thoughtcrime.securesms.backup.v2.BackupRepository.copyAttachmentToArchive import org.thoughtcrime.securesms.backup.v2.importer.ChatItemArchiveImporter import org.thoughtcrime.securesms.backup.v2.processor.AccountDataArchiveProcessor import org.thoughtcrime.securesms.backup.v2.processor.AdHocCallArchiveProcessor @@ -1454,6 +1455,13 @@ object BackupRepository { } } + @WorkerThread + fun getBackupLevelConfiguration(): SubscriptionsConfiguration.BackupLevelConfiguration? { + val config = getSubscriptionsConfiguration() + + return config.backupConfiguration.backupLevelConfigurationMap[SubscriptionsConfiguration.BACKUPS_LEVEL] + } + @WorkerThread private fun getFreeType(): MessageBackupsType.Free { val config = getSubscriptionsConfiguration() @@ -1464,10 +1472,8 @@ object BackupRepository { } private suspend fun getPaidType(): MessageBackupsType.Paid? { - val config = getSubscriptionsConfiguration() val product = AppDependencies.billingApi.queryProduct() ?: return null - - val backupLevelConfiguration = config.backupConfiguration.backupLevelConfigurationMap[SubscriptionsConfiguration.BACKUPS_LEVEL] ?: return null + val backupLevelConfiguration = getBackupLevelConfiguration() ?: return null return MessageBackupsType.Paid( pricePerMonth = product.price, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt index 2622153ab4..235b87cfa8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/BackupsSettingsViewModel.kt @@ -26,11 +26,11 @@ import org.thoughtcrime.securesms.backup.v2.MessageBackupTier import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType import org.thoughtcrime.securesms.components.settings.app.subscription.RecurringInAppPaymentRepository import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord -import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.InternetConnectionObserver import org.thoughtcrime.securesms.util.RemoteConfig import java.util.Currency +import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -79,8 +79,8 @@ class BackupsSettingsViewModel : ViewModel() { @WorkerThread private fun loadEnabledState(): Job { return viewModelScope.launch(SignalDispatchers.IO) { - if (!RemoteConfig.messageBackups || !AppDependencies.billingApi.isApiAvailable()) { - Log.w(TAG, "Paid backups are not available on this device.") + if (!RemoteConfig.messageBackups) { + Log.w(TAG, "Remote backups are not available on this device.") internalStateFlow.update { it.copy(enabledState = BackupsSettingsState.EnabledState.NotAvailable, showBackupTierInternalOverride = false) } } else { val enabledState = when (SignalStore.backup.backupTier) { @@ -117,10 +117,11 @@ class BackupsSettingsViewModel : ViewModel() { } } - private suspend fun getEnabledStateForPaidTier(): BackupsSettingsState.EnabledState { + @WorkerThread + private fun getEnabledStateForPaidTier(): BackupsSettingsState.EnabledState { return try { Log.d(TAG, "Attempting to grab enabled state for paid tier.") - val backupType = BackupRepository.getBackupsType(MessageBackupTier.PAID) as MessageBackupsType.Paid + val backupConfiguration = BackupRepository.getBackupLevelConfiguration() ?: return BackupsSettingsState.EnabledState.Failed Log.d(TAG, "Retrieved backup type. Grabbing active subscription...") val activeSubscription = RecurringInAppPaymentRepository.getActiveSubscriptionSync(InAppPaymentSubscriberRecord.Type.BACKUP).getOrThrow() @@ -135,8 +136,8 @@ class BackupsSettingsViewModel : ViewModel() { activeSubscription.activeSubscription.amount, Currency.getInstance(activeSubscription.activeSubscription.currency) ), - storageAllowanceBytes = backupType.storageAllowanceBytes, - mediaTtl = backupType.mediaTtl + storageAllowanceBytes = backupConfiguration.storageAllowanceBytes, + mediaTtl = backupConfiguration.mediaTtlDays.days ) ) } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt index 4839803598..b72a6ba30e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/backups/remote/RemoteBackupsSettingsFragment.kt @@ -72,7 +72,6 @@ import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import com.google.android.material.progressindicator.LinearProgressIndicator import org.signal.core.ui.compose.Buttons import org.signal.core.ui.compose.Dialogs import org.signal.core.ui.compose.Dividers @@ -105,6 +104,7 @@ import org.thoughtcrime.securesms.components.compose.TextWithBetaLabel import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity import org.thoughtcrime.securesms.components.settings.app.subscription.MessageBackupsCheckoutLauncher.createBackupsCheckoutLauncher import org.thoughtcrime.securesms.compose.ComposeFragment +import org.thoughtcrime.securesms.compose.StatusBarColorNestedScrollConnection import org.thoughtcrime.securesms.help.HelpFragment import org.thoughtcrime.securesms.keyvalue.protos.ArchiveUploadProgressState import org.thoughtcrime.securesms.payments.FiatMoneyUtil @@ -160,7 +160,8 @@ class RemoteBackupsSettingsFragment : ComposeFragment() { backupMediaSize = state.backupMediaSize, backupState = state.backupState, backupRestoreState = restoreState, - hasRedemptionError = state.hasRedemptionError + hasRedemptionError = state.hasRedemptionError, + statusBarColorNestedScrollConnection = remember { StatusBarColorNestedScrollConnection(requireActivity()) } ) } @@ -370,7 +371,8 @@ private fun RemoteBackupsSettingsContent( contentCallbacks: ContentCallbacks, backupProgress: ArchiveUploadProgressState?, backupMediaSize: Long, - hasRedemptionError: Boolean + hasRedemptionError: Boolean, + statusBarColorNestedScrollConnection: StatusBarColorNestedScrollConnection? ) { val snackbarHostState = remember { SnackbarHostState() @@ -391,7 +393,15 @@ private fun RemoteBackupsSettingsContent( scrollBehavior = scrollBehavior ) }, - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + modifier = Modifier + .then( + if (statusBarColorNestedScrollConnection != null) { + Modifier.nestedScroll(statusBarColorNestedScrollConnection) + } else { + Modifier + } + ) + .nestedScroll(scrollBehavior.nestedScrollConnection), snackbarHost = { Snackbars.Host(snackbarHostState = snackbarHostState) } @@ -1465,7 +1475,8 @@ private fun RemoteBackupsSettingsContentPreview() { messageBackupsType = MessageBackupsType.Free(mediaRetentionDays = 30) ), backupRestoreState = BackupRestoreState.FromBackupStatusData(BackupStatusData.CouldNotCompleteBackup), - hasRedemptionError = true + hasRedemptionError = true, + statusBarColorNestedScrollConnection = null ) } }